On 10/12/01 12:46 PM, "Henning P. Schmiedehausen" <[EMAIL PROTECTED]>
wrote:

> Hi,
> 
> this question may sound strange to you but as I was hunting a stupid
> bug in a TDK application of mine which uses Velocity, I was stumbling
> across the following behaviour.
> 
> In my understanding, a "reference" is an object in the velocity
> context. Existing as in "there is a key in the hash table for it".

No - "is there a non null Object in the context for that key" is the better
way to think of it.

> Imagine my surprise of the output of the following program:
> 
> --- cut --- veltest2.java --- cut ---
> import java.io.StringWriter;
> import org.apache.velocity.app.Velocity;
> import org.apache.velocity.VelocityContext;
> 
> public class veltest2
> {
> public static void main( String args[] )
> {
>   Velocity v = new Velocity();
> 
>   try {
>     v.init();
> 
>     VelocityContext vc = new VelocityContext();
> 
>     // ----- test  code -----
> 
>     vc.put("val1", "I am a value");
>     vc.put("val2", null);
> 
>     // ----- test  code -----
> 
>     StringWriter w = new StringWriter();
>     
>     v.mergeTemplate("veltest2.vm", "iso-8859-1", vc, w);
>     System.out.println(w);
>   } catch(Exception e) {
>     System.err.println("Oops: "+e);
>   }
> }
> }
> --- cut --- veltest2.java --- cut ---
> 
> --- cut --- veltest2.vm --- cut ---
> Begin Template
> 
> Val1: $val1
> Val2: $val2
> Val3: $val3
> 
> Val!1: $!val1
> Val!2: $!val2
> Val!3: $!val3
> 
> End Template
> --- cut --- veltest2.vm --- cut ---
> 
> I thought of:
> 
> --- cut ---
> Begin Template
> 
> Val1: I am a value
> Val2: null
> Val3: $val3
> 
> Val!1: I am a value
> Val!2: 
> Val!3: 
> 
> End Template
> --- cut ---
> 
> and got:
> 
> --- cut ---
> Begin Template
> 
> Val1: I am a value
> Val2: $val2
> Val3: $val3
> 
> Val!1: I am a value
> Val!2: 
> Val!3: 
> 
> End Template
> --- cut ---
> 
> 
> So, the "val2" seems to be dropped from the context. In fact, it
> wasn't. It was never put in:

That's right.
 
> In o.a.v.context.AbstractContext:
> 
> --- cut ---
> /**
> * Adds a name/value pair to the context.
> * 
> * @param key   The name to key the provided value with.
> * @param value The corresponding value.
> * @return Object that was replaced in the the Context if
> *         applicable or null if not.
> */
> public Object put(String key, Object value)
> {
>   /*
>    * don't even continue if key or value is null
>    */
> 
>   if (key == null)
>   {
>       return null;
>   }
>   else if (value == null)
>   {
>       return null;
>   }
>   
>   return internalPut(key, value);
> }
> --- cut ---
> 
> Ugh! I could live with "dropping if key is null", because putting a
> null key into the context could lead to all kinds of naughty things,
> but null-value?
> 
> I know, this behaviour is in there since at least 1.0.1 (first release
> I checked) and we want to keep the stuff stable (yadda, yadda, yadda,
> you don't need to tell me, Jon :-) ), but is this sane?

Yep :)

What's the difference between

Map m;

m.put("foo", null);
 
m.get("foo");
m.get("bar");

To velocity, there is nothing in the context.  We don't check for the
existance of a key, we check for the existance of the value.


> I have the following situation:
> 
> Business logic does some computation and finally has "a thingy". The
> business logic now does (in a Turbine screen):
> 
> ctx.put("thingy", th);
> 
> and I leave it up to a Tool in the Velocity context to render the thingy
> for the page:
> 
> 
> --- cut ---
> <TR>$!thingytool.render($thingy)</TR>
> --- cut ---
> 
> As I understood all the "MVC" methodology and the "this is wrong you
> must do it this way" posts on various jakarta lists, this is the right
> way to do. :-)
> 
> But wait. There is the case that the BL encounters an error. This is
> perfectly fine, then the "th" above is null. My tool is perfectly able
> to deal with a null "$th" thingy and would print "<the computation was
> not successful>" in this case. It never gets the chance. I have to resort
> to this (horrors):
> 
> #if($!th)
> <TR>$thingytool.reportError</TR>
> #else
> <TR>$!thingytool.render($th)</TR>
> #end
> 
> just because I can't put a "null" value into the context? For me,
> thingytool is part of the "V" of MVC, so it may well contain the error
> reporting.

Well, thingytool could throw an exception, the BL could throw an exception,
such that instead of rendering the template, which you can't because you
can't make all the data objects you need, you render an error page, or try
again, or whatever.
 
> At the moment there is no way to decide for a tool which gets driven
> from the context in a template to decide between
> 
> "there is an object for 'thingy'"
> "there is an object for 'thingy' but it is null"
> "there never was any 'thingy'"
> 
> because the last two cases are folded into "there never was any
> 'thingy'". IMHO there should really be a way to differenciate between
> the three possibilities.
> 
> 
> Question: What would really break if we relax the restriction of
> "putting null values" into the context? As far as I can see, there is
> some work to do in o.a.v.runtime.parser.node.ASTReference, which I'm
> more than willing to do over the weekend. Maybe with a property which
> defaults to "don't put null values into the context"? I would really
> need this (And it would even help the Intake Tool from Turbine which
> should bring Jon firmly on my side. ;-) Hint: mapTo(null) == getDefault() )

It's not an implementation issue :)
 
> Any opinions about this? Or am I just chasing white elephants and
> there is "a better way to do this"?

To me, it appears that you want the template engine to make it easier to
write clean templates because your MC part of MVC can't deal with problems
in gathering the data, and you are pushing this down to V.

My gut says that if MC and V agree that some set of objects are in the
context, then it is the responsibility of the MC to ensure they are there,
or they don't render the template for which the agreement was made.

However, this is somewhat rigid formalism, but it is in the context of a MVC
framework that you brought this up.

Therefore, since you have a framework that doesn't support that idea of a
strong contract, why not just make your own Context implementation that does
what you want?  That is the point of the Context stuff, so that applications
can tailor it to their specific needs.

You can make the context that you implement log the fact that something is
null, and supply whatever default value you choose.

Geir

-- 
Geir Magnusson Jr.     [EMAIL PROTECTED]
System and Software Consulting
"They that can give up essential liberty to obtain a little temporary safety
deserve neither liberty nor safety." - Benjamin Franklin


Reply via email to