On Tue, 2007-12-11 at 11:09 -0700, Andrew Robinson wrote:
> On Dec 11, 2007 11:02 AM, simon <[EMAIL PROTECTED]> wrote:
> > I think the variable evaluation is basically a recursive treewalk of an
> > expression-tree.
> >
> > So it evaluates
> > (a) ComplexValue{ base: expr1, prop:.treeModel }
> > (b) where expr1 is ComplexValue { base: expr2, prop:.foo }
> > (c) where expr2 is SimpleValue { bean }
> >
> > (a) calls (b) which calls (c) in a normal recursive manner.
> >
> > Step (c) is succeeding. Step (b) then resolves to null, and returns
> > that. Step (a) then complains that its "base" is null. But unfortunately
> > calling "tostring" on expr1 is just returning ".foo", leading to a
> > less-than-optimal error message.
> >
> > In other words, "base" does not mean the very first variable in the
> > expression, but instead the previous expression before the one that
> > could not be evaluated.
> >
> > Sorry Dave, this is probably more than you wanted to know :-).
> >
> > I think this just means that #{bean.foo} is null. Although it is
> > interesting how that might happen when you have the expression nested
> > inside a component with:
> > rendered="#{bean.foo != null}"
>
> The error is happening at tag time, not render time from the posted
> stack trace.
Ah.. and here is the problem code from TreeTag, which is the taghandler
class for the tomahawk tree2 component:
public int doStartTag() throws JspException {
FacesContext context = FacesContext.getCurrentInstance();
if (value != null) {
ValueBinding valueBinding = context.getApplication()
.createValueBinding(value);
TreeModel treeModel = (TreeModel)
(valueBinding.getValue(context));
if (treeModel == null) {
// create default model
treeModel = new DefaultTreeModel();
valueBinding.setValue(context, treeModel);
}
}
It looks like tree2 does a sort of "component binding" type thing, where
at component creation time it tries to retrieve the treeModel via the
EL, and if it is null then it creates one itself and assigns that via
the EL.
But this all happens at component creation, not at component render. So
it runs even when the tree2 is nested inside a component that has
rendered=false.
That doesn't feel like good design to me, but it is what it is. And it
does explain what Dave is getting: #{base.foo} is indeed null, so this
is failing.
> > > > <h:panelGroup rendered="#{bean.foo != null}">
> > > >
> > > > <t:tree value="#{bean.foo.treeModel}">
> > > > ...
> > > > </t:tree>
> > > >
> > > > </h:panelGroup>
> > > >
> > > > bean is not null.
> > > > Why did I got the following error:
> > > >
> > > > javax.faces.el.PropertyNotFoundException: Base is null: .foo
> > > > at
> > > > org.apache.myfaces.el.ValueBindingImpl.resolveToBaseAndProperty(ValueBindingImpl.java:477)
> > > > at
> > > > org.apache.myfaces.el.ValueBindingImpl.setValue(ValueBindingImpl.java:251)
> > > > at
> > > > org.apache.myfaces.custom.tree.taglib.TreeTag.doStartTag(TreeTag.java:349)
Dave, it looks like you'll have to make sure that the tree2 value
attribute points to a bean that always exists.
If that is really difficult, then perhaps you can get away with using
something like:
<c:if ...>
<f:subview id="treeview">
<t:tree ..../>
<f:subview>
</c:if>
c:if is not generally recommended with JSF, but if you wrap the contents
with a subview tag it might be ok..
Regards,
Simon