Re: A nullability question

Daniel Dekany <[email protected]>
Newsgroups gmane.comp.web.freemarker.user
Message-ID <[email protected]>
Monday, May 30, 2011, 12:19:54 PM, Eirik Lygre wrote:

> Hi,
>
> For one of our FreeMarker scenarios, we use a model object with a signature
> like this:
>
>    class MyNumberModel implements TemplateHashModelEx, TemplateNumberModel {
>       ...
>       public Number getAsNumber() {
>          return functionThatReturnsActualNumber();
>       }
>    }
>
> In general, the HashModel returns lots of metadata (like datatype, length,
> name, origin, etc), while the NumberModel returns the actual value. My
> question is how to best handle null values, to that "${field!0}" works properly.
>
> I was hoping that having getAsNumber() return "null" would be the proper
> thing to do: Then, we can reuse the model for all numeric types, regardless
> of their actual value, and still access the metadata even when the value is
> null. This doesn't seem to be the case, though: Rather, if
> functionThatReturnsActualNumber() returns null, we get this stack trace:
>
>    freemarker.template.TemplateException: value!0 evaluated to null number.
>         at
> freemarker.core.EvaluationUtil.getNumber(EvaluationUtil.java:117)
>         ...
>
> The alternative way is to actually have two different models, and instantiate
> them as required. This is shown below, but it complicates our code quite a
> bit, since we can no longer just instantiate the model object based on our
> underlying data type, but also must care for the underlying *value*:
>
>    class MyNullNumberModel implements TemplateHashModelEx {
>       ...
>    }
>
>
>    class MyNotNullNumberModel extends MyNullNumberModel
>                               implements TemplateNumberModel {
>       ...
>       public Number getAsNumber() {
>          return functionThatReturnsActualNumber();
>       }
>    }
>
> So, the questions are:
>
> 1) Currently, will I have to do the two-different-model-classes approach,
>    or am I missing something?
> 2) In the future, will this change & become simpler?
>
> Eirik

Hmm... I see the problem, but I'm afraid FreeMarker has no operator
for thus. And I think there's a conceptual misunderstanding regarding
what the ! operator meant to do. The ! operator doesn't check if the
left-hand operand has a *scalar* value (let alone if it has a
numerical value), it simply checks if it has any kind of value at all
(but null). It's typically used to checking if we have a foo variable,
or it's missing from the data-model (in which case
TemplateHashModel.get(key) returns null). So what you want here would
be something like foo?has_numberical_value(0), but there's no such
thing in FreeMarker (nor you would want to type it if it had :) ).

So, the second solution wouldn't work either. If in foo!0 the foo
variable is a MyNullNumberModel, since the hash exists, it will just
evaluate to foo, not to 0.

So I'm afraid you will have to have a sub-variable called, for
example, "value". This would be either a TemplateNumberModel or null.
Then you can write this:

  ${foo.value?0}

while you will also have

  ${foo.datatype}
  ${foo.origin}

and so on. On the same time, you can also have ${foo}, which prints a
number (because when it comes to converting to sting, FM will prefer
the numerical value over the hash value), but ! will not work with
that since foo exists even if it's not a number but just a hash.

Do not return null with getAsNumber(). I don't think FM was designed
wit that case in mind, so it pretty much a call for a NPE, even if it
happens to be treated differently as it turns out. Some may point out
that a hack like ${(foo + 0)!0} works (or does it?), but I wouldn't
build on anything like that. It's pretty much an implementation
detail, if not a bug. So it can change.

BTW, if you really must spare the keystrokes when doing things like
${foo.value?0}, then foo could also implement TemplateMethodModelEx,
and then you could write ${foo(0)}. Cryptic, but doable and fast. Or
another solution which is a bit longer is ${foo.or(0)}.

-- 
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
vRanger cuts backup time in half-while increasing security.
With the market-leading solution for virtual backup and recovery, 
you get blazing-fast, flexible, and affordable data protection.
Download your free trial now. 
http://p.sf.net/sfu/quest-d2dcopy1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.