Re: Odd observation during debugging

Nathan Bubna <[email protected]>
Newsgroups gmane.comp.jakarta.velocity.user
Message-ID <CAFyaDjE8BFW-RviZy2hNkKTr4Q2fyjBi8-fFiX1uhdpJtiMsqA@mail.gmail.com>
Just set:
directive.if.tostring.nullcheck = false

See VELOCITY-731 and VELOCITY-692 and others...

On Wed, Jul 11, 2012 at 9:13 AM, Christopher Schultz
<[email protected]> wrote:
> All,
>
> I recently started getting intermittent OOMEs in my webapp that seem to
> be completely recoverable. The stack traces look like this:
>
> java.lang.OutOfMemoryError: Java heap space
>         at java.util.Arrays.copyOf(Arrays.java:2882)
>         at
> java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100)
>         at
> java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390
> )
>         at java.lang.StringBuilder.append(StringBuilder.java:119)
>         at java.lang.StringBuilder.append(StringBuilder.java:115)
>         at
> java.util.AbstractCollection.toString(AbstractCollection.java:422)
>         at
> org.apache.velocity.runtime.parser.node.ASTReference.evaluate(ASTReference.java:547)
>     [...]
>
> This happens so rarely, it's hard to catch, and it's fairly obvious what
> is happening: toString is being called on a really huge List. We try not
> to use really huge lists, but I suppose there is some potential danger
> in rare instances. I want to find those instances.
>
> Velocity 1.7, Tools 2.0 (plus some committed bugfixes that haven't made
> it into an official release, yet).
>
> So I thought I'd add some trickery to my VelocityContexts: We use our
> own subclasss of VelocityLayoutServlet for a number of things, and I
> have overridden the createContext() to wrap the Context the
> super.createContext() returns in a ChainedContext (btw, that's
> deprecated but doesn't document a replacement -- what should I use?). My
> wrapper wraps all List and Set objects in yet another set of wrappers
> which essentially pass-through everything except that their toString
> methods throw an exception: there should be no reason that a List or Set
> should have toString() called on it, because they should only be
> iterated over, for instance.
>
> But right on my login page, I see this exception after such instrumentation:
>
> SEVERE: Servlet.service() for servlet velocity threw exception
> org.apache.velocity.exception.VelocityException: Reference evaluation
> threw an exception at /layout/header.vm[line 18, column 5]
>         at
> org.apache.velocity.runtime.parser.node.ASTReference.evaluate(ASTRefe
> rence.java:551)
>         at
> org.apache.velocity.runtime.parser.node.ASTExpression.evaluate(ASTExp
> ression.java:62)
>         at
> org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfSt
> atement.java:85)
>         at
> org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.
> java:342)
>         at
> org.apache.velocity.runtime.directive.Parse.render(Parse.java:260)
>         at
> org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirect
> ive.java:207)
>         at
> org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.
> java:342)
>         at org.apache.velocity.Template.merge(Template.java:356)
>         [....]
> Caused by: java.lang.IllegalStateException: Request /myapp/login.vm,
> called toString on key 'extraStylesheets'
>         at
> com.chadis.web.servlet.VelocityLayoutServlet$WrappedList.toString(VelocityLayoutServlet.java:220)
>         at
> org.apache.velocity.runtime.parser.node.ASTReference.evaluate(ASTReference.java:547)
>
> If I look at everything that references the key 'extraStylesheets' in my
> login page (and the header, etc.), I get only these:
>
> login.vm only includes these references:
> #set($extraStylesheets = ['/includes/css/login.css'])
>
> I'm using VelocityLayoutServlet which is using my layouts/Default.vm (no
> references to 'extraStylesheets') which includes (via #parse)
> 'header.vm' which has this to say:
>
> #if($extraStylesheets)
>         #foreach($stylesheet in $extraStylesheets)
>     <link type="text/css" href="$link.setRelative($stylesheet)"
> rel="stylesheet" />
>         #end
> #end
>
> ...and that's it. Given the upper stack trace it seems that the #if() is
> evaluating the argument by converting it into a String for evaluation.
> Is that intentional? I always used "#if($foo)" to check to see if $foo
> had a value of any kind -- that is, if it was non-null (and non-false)
> but it appears that the value is being converted into a String for ...
> what purpose?
>
> I know a lot of changes have occurred over the years and that
> String-conversion is something that has seen some of that action. Is
> there a "better" way of determining if a List (or whatever) has a value?
> That is, without converting it to a String, first?
>
> One can argue that I shouldn't have Lists of objects so large that
> converting them to a String will cause an OOME, but the calling of
> toString on these Lists is certainly surprising.
>
> Thanks,
> -chris
>
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.