Intershop: checking for not null in .isml template

1.4k views Asked by At

I'm not finding a function to test for the existence of a value in the ISML template code. There's 'isDefined' but not 'isNull'.

isDefined returns true on null values:

      <isset name="woot" value="" scope="request">

       <isif condition="#isDefined(woot)#">
           <h1>woot</h1>
       </isif>

For now I'm using:

 <isif condition="#woot EQ null#">

or

 <isif condition="#woot EQ ''#">

I don't know if this will work for Boolean values.

1

There are 1 answers

1
Willem Evertse On BEST ANSWER

isDefined is how you would check for a null value. In AbstractTemplate you have the method isDefined(Object anObject) that is called. Checkout the compiled jsp and java versions of your isml template.

In AbstractTemplate

public Boolean isDefined(Object anObject){
    ...
    return anObject != null ? Boolean.TRUE : Boolean.FALSE;
}

The code in your example is a bit misleading, it doesn't actually test for a null reference. Bear with me.

First statement :

<isset name="woot" value="" scope="request">

Compiles to :

Object temp_obj = (""); 
getPipelineDictionary().put("woot", temp_obj);

This just sets the woot variable to an empty string. If you add the following scriptlet to your isml you will see that it really isn't a null.

Disclaimer: don't use scriptlets in production code, this is only for demonstrating a point

<%
    Object woot = getPipelineDictionary().get("woot");
    out.print(woot == null); //print false
%>

Second line:

<isif condition="#isDefined(woot)#">

Evaluates if the variable exist and it does. It has an empty string as a value, not null like you might think.

So what happens here then?

<isif condition="#woot EQ null#">

Looking at the compiled version:

context.getFormattedValue(getObject("woot"),null).equals(context.getFormattedValue(getObject("null"),null))

The context.getFormattedValue(getObject("null"),null) is the important bit here. It tries to retreive the variable called null, it doesnt exist so returns null. The getFormattedValue method then returns an empty string for the null argument (see TemplateExecutionConfig::getFormattedValue). The whole statement then evals to true. Not because woot is null, but because you are comparing it to a variable that doesnt exist, so you are inadvertently evaluating two empty strings. This behaviour is consistent with the EQ operator because it is use to compare strings.

You would get the same result if u would use this statement too.

<isif condition="#woot EQ iDontExistButImAlsoNotNull#"> //true

The third statement compares the woot variable to an empty string value, which returns true.

<isif condition="#woot EQ ''#">

Compiled version:

context.getFormattedValue(getObject("woot"),null).equals(context.getFormattedValue("",null))

So the real problem is that woot doesn't have the literal value null. See the following code:

<isset name="foo" value="#IDontExitPrettySureAboutThat#" scope="request">
<%
    Object foo = getPipelineDictionary().get("foo");
    out.print("foo is null? ");
    out.print(foo == null);
    //prints : foo is null? true
%>
<isif condition="#isDefined(foo)#">
    <h1>foo1</h1> //is never printed
</isif>

I'm abusing the fact that IDontExitPrettySureAboutThat doesn't exist to set a null value to foo. isDefined then starts to work like you would expect. That is until someone initializes my variable to something other than null.

I wouldn't advocate that you use this method, however. I think the best advice is not to use null to represent a missing value or invalid state. This thread goes into some details on this topic.