Is there a way to throw an exception from within a facelet? Background: I've a component using a customised converter as parameter. So I call the component as
#Named
#RequestScoped
public class CustomConverter implements Converter<String>
...
...
<ui:param
name="pConverter"
value="#{customConverter}" />
...
But when there's a typo in the param value e.g.
...
<ui:param
name="pConverter"
value="#{custoMConverter}" /> <!-- custoMConverter instead of customConverter -->
...
the converter is consequently not working but no exception is thrown. Now I would like to throw an exception from within the component if the converter is empty in such a case. How to do that?
Why is a non existent element not throwing an exception at all?
<h:outputText value="#{fooBean.foo}" />
There's no exception if the bean fooBean doesn't exist. Why not?
Thanks in advance.
I've found a solution.
#Named
#ApplicationScoped
public class ApplicationBean {
public final void checkExistenceAndThrow(final Object o) {
if (Objects.isNull(o)) {
throw new NullPointerException();
}
}
}
Then in the component check for the existence of the converter:
<h:outputText
value="#{applicationBean.checkExistenceAndThrow(pConverter)}"
style="display: none;" />
So the throwing of the exception is delegated to the bean.
Related
We use commandButtons inside a c:forEach tag, where the button's action receives the forEach var attribute as a parameter like this:
<c:forEach var="myItem" items="#{myModel}">
<h:commandButton
action="#{myController.process(myItem)}"
value="#{myItem.name}" />
</c:forEach>
This works just fine. If we wrap the commandButton in a composite component, it does not work anymore, though: The controller gets called, but parameter is always null.
Here is an example of a c:forEach Tag containing a button and composite component wrapping a button. The first one works, the second one does not.
<c:forEach var="myItem" items="#{myModel}">
<h:commandButton
action="#{myController.process(myItem)}"
value="#{myItem.name}" />
<my:mybutton
action="#{myController.process(myItem)}"
value="#{myItem.name}" />
</c:forEach>
with the following my:mybutton implementation:
<composite:interface>
<composite:attribute name="action" required="true" targets="button" />
<composite:attribute name="value" required="true" />
</composite:interface>
<composite:implementation>
<h:commandButton id="button"
value="#{cc.attrs.value}">
</h:commandButton>
</composite:implementation>
Please Note, that the button's value attribute, which is also bound to the c:ForEach var, works just fine. It is only the action, propagated through the composite component's targets mechanism, that does not get evaluated correctly.
Can anoymone please explain, why this happens and how to fix this?
We are on mojarra 2.2.8, el-api 2.2.5, tomcat 8.0.
This is caused by a bug in Mojarra or perhaps an oversight in the JSF specification with regard to retargeting method expressions for composite components.
The work around is the below ViewDeclarationLanguage.
public class FaceletViewHandlingStrategyPatch extends ViewDeclarationLanguageFactory {
private ViewDeclarationLanguageFactory wrapped;
public FaceletViewHandlingStrategyPatch(ViewDeclarationLanguageFactory wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewDeclarationLanguage getViewDeclarationLanguage(String viewId) {
return new FaceletViewHandlingStrategyWithRetargetMethodExpressionsPatch(getWrapped().getViewDeclarationLanguage(viewId));
}
#Override
public ViewDeclarationLanguageFactory getWrapped() {
return wrapped;
}
private class FaceletViewHandlingStrategyWithRetargetMethodExpressionsPatch extends ViewDeclarationLanguageWrapper {
private ViewDeclarationLanguage wrapped;
public FaceletViewHandlingStrategyWithRetargetMethodExpressionsPatch(ViewDeclarationLanguage wrapped) {
this.wrapped = wrapped;
}
#Override
public void retargetMethodExpressions(FacesContext context, UIComponent topLevelComponent) {
super.retargetMethodExpressions(new FacesContextWithFaceletContextAsELContext(context), topLevelComponent);
}
#Override
public ViewDeclarationLanguage getWrapped() {
return wrapped;
}
}
private class FacesContextWithFaceletContextAsELContext extends FacesContextWrapper {
private FacesContext wrapped;
public FacesContextWithFaceletContextAsELContext(FacesContext wrapped) {
this.wrapped = wrapped;
}
#Override
public ELContext getELContext() {
boolean isViewBuildTime = TRUE.equals(getWrapped().getAttributes().get(IS_BUILDING_INITIAL_STATE));
FaceletContext faceletContext = (FaceletContext) getWrapped().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
return (isViewBuildTime && faceletContext != null) ? faceletContext : super.getELContext();
}
#Override
public FacesContext getWrapped() {
return wrapped;
}
}
}
Install it as below in faces-config.xml:
<factory>
<view-declaration-language-factory>com.example.FaceletViewHandlingStrategyPatch</view-declaration-language-factory>
</factory>
How I nailed down it?
We have confirmed that the problem is that the method expression argument became null when the action is invoked in a composite component while the action itself is declared in another composite component.
<h:form>
<my:forEachComposite items="#{['one', 'two', 'three']}" />
</h:form>
<cc:interface>
<cc:attribute name="items" required="true" />
</cc:interface>
<cc:implementation>
<c:forEach items="#{cc.attrs.items}" var="item">
<h:commandButton id="regularButton" value="regular button" action="#{bean.action(item)}" />
<my:buttonComposite value="cc button" action="#{bean.action(item)}" />
</c:forEach>
</cc:implementation>
<cc:interface>
<cc:attribute name="action" required="true" targets="compositeButton" />
<cc:actionSource name=""></cc:actionSource>
<cc:attribute name="value" required="true" />
</cc:interface>
<cc:implementation>
<h:commandButton id="compositeButton" value="#{cc.attrs.value}" />
</cc:implementation>
First thing I did was locating the code who's responsible for creating the MethodExpression instance behind #{bean.action(item)}. I know it's normally created via ExpressionFactory#createMethodExpression(). I also know that all EL context variables are normally provided via ELContext#getVariableMapper(). So I placed a debug breakpoint in createMethodExpression().
In the call stack we can inspect the ELContext#getVariableMapper() and also who's responsible for creating the MethodExpression. In a test page with a composite component in turn nesting one regular command button and one composite command button we can see the following difference in ELContext:
Regular button:
We can see that the regular button uses DefaultFaceletContext as ELContext and that the VariableMapper contains the right item variable.
Composite button:
We can see that the composite button uses standard ELContextImpl as ELContext and that the VariableMapper doesn't contain the right item variable. So we need to go some steps back in the call stack to see where this standard ELContextImpl is coming from and why it's being used instead of DefaultFaceletContext.
Once found where the particular ELContext implementation is created, we can find that it's obtained from FacesContext#getElContext(). But this does not represent the EL context of the composite component! This is represented by the current FaceletContext. So we need to go some more steps back to figure out why the FaceletContext isn't being passed down.
We can see here that CompositeComponentTagHandler#applyNextHander() doesn't pass through the FaceletContext but the FacesContext instead. This is the exact part which might have been an oversight in the JSF specification. The ViewDeclarationLanguage#retargetMethodExpressions() should have asked for another argument, representing the actual ELContext involved.
But it is what it is. We can't change the spec on the fly right now. Best what we can do is to report an issue to them.
The above shown FaceletViewHandlingStrategyPatch works as follows by ultimately overriding the FacesContext#getELContext() as below:
#Override
public ELContext getELContext() {
boolean isViewBuildTime = TRUE.equals(getWrapped().getAttributes().get(IS_BUILDING_INITIAL_STATE));
FaceletContext faceletContext = (FaceletContext) getWrapped().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
return (isViewBuildTime && faceletContext != null) ? faceletContext : super.getELContext();
}
You see, it checks if JSF is currently building the view and if there's a FaceletContext present. If so, then return the FaceletContext instead of the standard ELContext implementation (note that FaceletContext just extends ELContext). This way the MethodExpression will be created with the right ELContext holding the right VariableMapper.
I try learn JSF and faced with problem.
I did use Servlet 2.5, JDK 1.6 and JSF 2.0.6 (com.sun.faces version from pom file).
I have a simple JSF page that has a <h:inputText/> tag for interaction with user
I expect what user fill this h:inputText then click on h:commandButton and on server side i will get backing bean with updated value.
But in my case lifecycle of JSF breaks on process validations, move to render
response and show to user "Parser error!" message
I.e. for simple h:inputText without any validator and converter i receive error message from server side about parsing of h:inputText value.
After some time i figured out what i can create my own converter which will not modify object, just pass String through himself.
I did add my realization of converter to <h:inputText/> and this work.
Question:
In all examples in books and other tutorials nobody used custom converter for <h:inputText/> if inputText is representation of String value of backing bean.
Why all of this tutorials and examples not working for me without custom converter? Where my mistake?
Source codes:
index.xhtml without converter, not worked for me:
<h:form id="UserForm">
<h:outputText value="Insert your first name:" />
<h:inputText id="userNameID" required="true" value="#{userBean.firstName}">
<f:validateLength minimum="5" maximum="25" />
</h:inputText>
<h:message showSummary="true" showDetail="false" for="userNameID" />
<h:commandButton id="submit" action="/view/validator/response?faces-redirect=true"
value="Submit" />
</h:form>
UserBean.java:
#ManagedBean(name = "userBean")
#SessionScoped
public class UserBean implements Serializable {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
MyConverter.java - dummy converter
#FacesConverter(value = "myConverter")
public class MyConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
index.xhtml with converter, worked as expected:
<h:form id="UserForm">
<h:outputText value="Insert your first name:" />
<h:inputText id="userNameID" required="true" value="#{userBean.firstName}" converter="myConverter">
<f:validateLength minimum="5" maximum="25" />
</h:inputText>
<h:message showSummary="true" showDetail="false" for="userNameID" />
<h:commandButton id="submit" action="/view/validator/response?faces-redirect=true"
value="Submit" />
</h:form>
The cause of the problem is not visible in the code posted so far, but the key symptom "it fails with a message coming from a so far unidentified converter while it succeeds with an explicit converter" suggests that you've elsewhere in the same project a #FacesConverter(forClass=String.class) which would run automatically on every single String property which doesn't have another converter explicitly specified.
First, I show my code:
XHTML page:
<h:body>
<h:form id="ffffffffff">
<p:inputText value="#{prueba.dato}" >
<p:ajax event="keyup" process="#this" />
</p:inputText>
</h:form>
</h:body>
Bean:
#ManagedBean
#ViewScoped
public class Prueba implements Serializable {
private String dato = "ASSSS";
public String getDato() {
return dato;
}
public void setDato(String dato) {
this.dato = dato;
System.out.println("DAAAAAA: " + dato);
}
public void listener() {
System.out.println("LISTENEEEEEEEEEEEEEEEEEEEEEEEEEE");
}
}
Converter
#FacesConverter
public class SnaCarreraConverter extends SelectItemsConverter {
//CODE
}
My problem, setDato is always getting a null value. But when I modify the converter to this:
#FacesConverter(forClass=SnaCarrera.class)
adding forClass resolve my problem, I don't know why this happens. Is The inputText trying to find a Converter without add the converter property?
First of all, the SelectItemsConverter is for <f:selectItems>. The <p:inputText> is not a <f:selectItems>. So the SelectItemsConverter is useless for the <p:inputText>. See also its documentation and showcase.
Second, it's normal to give the Converter implementation an ID or a "for-class" in order to use it. Otherwise you can't refer it in the <x:inputSomething converter> attribute, or in the <f:converter> tag, or you can't auto-associate it with a certain class. This requirement is totally unrelated to the SelectItemsConverter. It's just required by standard JSF spec.
This question already has answers here:
How can I add FacesMessage during page load? Using #PostConstruct does not seem to work
(3 answers)
Closed 8 years ago.
I want to display error messages when the user first requested the page. The error is set in the post construct method of the request scoped managed bean like the following:
#RequestScoped
public class MyBean {
private String name;
#PostConstruct
public void init() {
// some validations here
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "You have no credit!");
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, message);
context.renderResponse();
}
public String getName() {
return name;
}
}
and then in my JSF page:
<!-- I'm expecting the error you have no credit will be displayed here -->
<h:messages />
<h:form>
<h:inputText value="#{myBean.name}" />
</h:form>
When run in development stage, the JSF complaints that this is an unhandled messages:
"Project Stage[Development]: Unhandled Messages - You have no credit!"
Can you help me?
I was experiencing the same issue on WebSphere 7 with MyFaces JSF 2.1.
It appears as though WebSphere is flushing the buffer too early, so that the messages tag is rendered prior to the #PostConstruct method completing. I have not as yet found a way to alter WebSphere's behavior however by placing a getter-method in the managed bean to return an empty string and use a h:ouputText tag to use the value I now have a page which renders my messages.
e.g.
BackingBean.class
#ManagedBean
#RequestScopped
public class BackingBean {
public String getEmptyString { return ""; }
}
BackingBean.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head></h:head>
<body>
<h:outputText value="#{backingBean.emptyString"/>
...
</body>
</html>
I solved the same problem by putting the messages after the first declaration of the bean that is expected to produce the message you want to be shown. So in your example above instead of having this:
**<h:messages />**
<h:form>
<h:inputText value="#{myBean.name}" />
</h:form>
Try to make it like this:
<h:form>
<h:inputText value="#{myBean.name}" />
</h:form>
**<h:messages />**
Check BalusC's more detailed explanation here:
How can I add Faces Messages during #PostConstruct
Hope this helps
I have Facelet component and I have backing bean for it. When I include my component to some page I pass bean from page to my component:
<ui:include src="./WEB-INF/templates/myTemplate.xhtml">
<ui:param name="pageBean" value="#{thisPageBean}" />
</ui:include>
My component also have backing bean and I try to pass value from invoking page bean to my:
<c:set target="#{componentBean}" property="field" value="#{pageBean.field}" />
But this method doesn't work? There is some way to pass value from one bean to another?
I am trying create difficult custom component that must do some validation and other action on things that was pass to it? Maybe I am in wrong way?
You could pass the bean as an attribute on the component (I assume when you say "component" you are using ui:component).
For a component:
<ui:component binding="#{componentBean.myComponent}">
<f:attribute name="foo" value="#{pageBean.field}" />
<h:outputText value="#{componentBean.something}" />
</ui:component>
You could have a backing bean with these methods:
private Object field;
private UIComponent component;
public void setMyComponent(UIComponent c) { component = c; }
public UIComponent getMyComponent() { return component; }
private void lookupFields() {
field = component.getAttributes().get("foo");
}
public String getSomething() {
if (field == null) {
lookupFields();
}
return "" + field;
}
Not very elegant, but I'm not all that familiar with the mechanics of Facelets includes and this is the first thing that occurred to me. Note that the attributes might be persisted when the view is saved - I can't remember for stuff that gets set on the attributes map.
Usually you assign values to some input controls like:
<h:inputText value='#{pageBean.field}'/>
That implies both getting and setting the value of someField property.
Please provide details on what should determine the value of #{pageBean.field} in your case.
Here is some code from one of my facelets files. As you can see the value of the bean passed as a parameter, ie:
<ui:param name="bean" value="#{thisPageBean}" />
and the property of the bean, dto, can be accessed using the [dto] notation.
<h:panelGroup>
<h:selectOneMenu id="titleMenu" value="#{bean[dto].title}">
<f:selectItems value="#{suburbsMBean.titles}" />
</h:selectOneMenu>
<h:message for="titleMenu" styleClass="error" />
</h:panelGroup>
You can call bean methods with params in JSF 2.0
So you can try to just place the setter method in a comment like this:
<!-- #{componentBean.setField(pageBean.field)} -->
So when the page is loaded the setter method will be triggered.