Hey guys I made a patch to Velocity 1.7 to enable you to print out velocity
stack traces. If you dump a stack trace in a Java function that was called from
a velocity file, you usually see a bunch of calls to velocity parser functions
like this in the Java stack trace:
...
at
org.apache.velocity.runtime.parser.node.ASTIdentifier.execute(ASTIdentifier.java:209)
at
org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:280)
at
org.apache.velocity.runtime.parser.node.ASTReference.evaluate(ASTReference.java:530)
at
org.apache.velocity.runtime.parser.node.ASTExpression.evaluate(ASTExpression.java:62)
at
org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:85)
at
org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
at
org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:87)
at
org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
at
org.apache.velocity.runtime.directive.VelocimacroProxy.render(VelocimacroProxy.java:216)
at
org.apache.velocity.runtime.directive.RuntimeMacro.render(RuntimeMacro.java:312)
at
org.apache.velocity.runtime.directive.RuntimeMacro.render(RuntimeMacro.java:230)
at
org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirective.java:207)
at
org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:342)
at
org.apache.velocity.runtime.parser.node.ASTStringLiteral.value(ASTStringLiteral.java:330)
...
The velocity stack trace created by this patches is much more informative:
Velocity Stack Trace: Invocation of method 'getAvatarUrl' in class Member
at avatarUrl called at common/Macros.vm[line 426, column 29]
at simpleAvatarUrl called at common/Macros.vm[line 487, column 22]
at drawSimpleImage called at common/Macros.vm[line 487, column 3]
at simpleMemberAvatar called at site/photo_pane.vm[line 153, column 32]
at displayAvatarImage called at site/photo_pane.vm[line 162, column 3]
This sort of stack trace is very useful when debugging code and trying to
figure out which sequence of macros called into the currently executing Java
code that dumped out the Java stack trace. Please consider adding something
like this to a future release of Velocity - it would be very useful!
Thanks,
Luke
diff --git a/velocity-1.7/build/build.properties b/velocity-1.7/build/build.properties
index aba450e..c0852df 100644
--- a/velocity-1.7/build/build.properties
+++ b/velocity-1.7/build/build.properties
@@ -106,7 +106,7 @@ javadocs.ref.jsdk= http://java.sun.com/j2se/1.4.2/docs/api/
# they are not already present.
# Set skip.jar.loading to true to never download any dependency jar,
# or force.jar.loading to true to always download all dependency jars.
-skip.jar.loading= false
+skip.jar.loading= true
force.jar.loading= false
diff --git a/velocity-1.7/src/java/org/apache/velocity/context/ChainedInternalContextAdapter.java b/velocity-1.7/src/java/org/apache/velocity/context/ChainedInternalContextAdapter.java
index 1b5ccbf..a409071 100644
--- a/velocity-1.7/src/java/org/apache/velocity/context/ChainedInternalContextAdapter.java
+++ b/velocity-1.7/src/java/org/apache/velocity/context/ChainedInternalContextAdapter.java
@@ -193,6 +193,30 @@ public abstract class ChainedInternalContextAdapter implements InternalContextAd
}
/**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentMacroCall(java.lang.String)
+ */
+ public void pushCurrentMacroCall(String s)
+ {
+ innerContext.pushCurrentMacroCall(s);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentMacroCall()
+ */
+ public void popCurrentMacroCall()
+ {
+ innerContext.popCurrentMacroCall();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getMacroCallStack()
+ */
+ public Object[] getMacroCallStack()
+ {
+ return innerContext.getMacroCallStack();
+ }
+
+ /**
* @see org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object)
*/
public IntrospectionCacheData icacheGet(Object key)
diff --git a/velocity-1.7/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java b/velocity-1.7/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
index a2ef9f7..1f1ad96 100644
--- a/velocity-1.7/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
+++ b/velocity-1.7/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
@@ -191,6 +191,30 @@ public final class InternalContextAdapterImpl implements InternalContextAdapter
}
/**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentMacroCall(java.lang.String)
+ */
+ public void pushCurrentMacroCall(String s)
+ {
+ icb.pushCurrentMacroCall(s);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentMacroCall()
+ */
+ public void popCurrentMacroCall()
+ {
+ icb.popCurrentMacroCall();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getMacroCallStack()
+ */
+ public Object[] getMacroCallStack()
+ {
+ return icb.getMacroCallStack();
+ }
+
+ /**
* @see org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object)
*/
public IntrospectionCacheData icacheGet( Object key )
diff --git a/velocity-1.7/src/java/org/apache/velocity/context/InternalContextBase.java b/velocity-1.7/src/java/org/apache/velocity/context/InternalContextBase.java
index 4842ee5..aeca46b 100644
--- a/velocity-1.7/src/java/org/apache/velocity/context/InternalContextBase.java
+++ b/velocity-1.7/src/java/org/apache/velocity/context/InternalContextBase.java
@@ -63,6 +63,11 @@ class InternalContextBase implements InternalHousekeepingContext, InternalEventC
* Velocimacro name stack. The stack top contains the current macro name.
*/
private Stack macroNameStack = new Stack();
+
+ /**
+ * Velocimacro call stack. The stack top contains the current macro call.
+ */
+ private Stack macroCallStack = new Stack();
/**
* EventCartridge we are to carry. Set by application
@@ -176,6 +181,35 @@ class InternalContextBase implements InternalHousekeepingContext, InternalEventC
{
return macroNameStack.toArray();
}
+
+
+ /**
+ * set the current macro call on top of stack
+ *
+ * @param s current macro call
+ */
+ public void pushCurrentMacroCall( String s)
+ {
+ macroCallStack.push(s);
+ }
+
+ /**
+ * remove the current macro call from stack
+ */
+ public void popCurrentMacroCall()
+ {
+ macroCallStack.pop();
+ }
+
+ /**
+ * get the current macro call stack
+ *
+ * @return Object[] with the macro call stack contents.
+ */
+ public Object[] getMacroCallStack()
+ {
+ return macroCallStack.toArray();
+ }
/**
* returns an IntrospectionCache Data (@see IntrospectionCacheData)
diff --git a/velocity-1.7/src/java/org/apache/velocity/context/InternalHousekeepingContext.java b/velocity-1.7/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
index f77f1d4..b7e3017 100644
--- a/velocity-1.7/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
+++ b/velocity-1.7/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
@@ -100,6 +100,24 @@ interface InternalHousekeepingContext
Object[] getMacroNameStack();
/**
+ * set the current macro call on top of stack
+ *
+ * @param s current macro call
+ */
+ void pushCurrentMacroCall( String s);
+
+ /**
+ * remove the current macro call from stack
+ */
+ void popCurrentMacroCall();
+
+ /**
+ * Returns the macro call stack in form of an array.
+ *
+ * @return Object[] with the macro call stack contents.
+ */
+ Object[] getMacroCallStack();
+ /**
* returns an IntrospectionCache Data (@see IntrospectionCacheData)
* object if exists for the key
*
diff --git a/velocity-1.7/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java b/velocity-1.7/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
index 090b552..f51ebda 100644
--- a/velocity-1.7/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
+++ b/velocity-1.7/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
@@ -307,6 +307,7 @@ public class RuntimeMacro extends Directive
try
{
+ context.pushCurrentMacroCall(macroName + " called at " + Log.formatFileString(node));
preRender(context);
return vmProxy.render(context, writer, node, body);
}
@@ -340,6 +341,7 @@ public class RuntimeMacro extends Directive
finally
{
postRender(context);
+ context.popCurrentMacroCall();
}
}
else if (strictRef)
diff --git a/velocity-1.7/src/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java b/velocity-1.7/src/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java
index b236755..02aa5c0 100644
--- a/velocity-1.7/src/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java
+++ b/velocity-1.7/src/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java
@@ -28,6 +28,7 @@ import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.util.introspection.Info;
import org.apache.velocity.util.introspection.IntrospectionCacheData;
import org.apache.velocity.util.introspection.VelPropertyGet;
@@ -195,6 +196,16 @@ public class ASTIdentifier extends SimpleNode
*/
try
{
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Invocation of method '").append(vg.getMethodName()).append("' in ").append(o.getClass()).append("\n");
+ sb.append(" at ").append(identifier).append(" called at ").append(Log.formatFileString(this));
+ Object[] stack = context.getMacroCallStack();
+ for (int i = stack.length-1; i >=0; i--)
+ {
+ sb.append("\n at ").append(stack[i]);
+ }
+ context.put("VELOCITY_STACK", sb.toString());
return vg.invoke(o);
}
catch(InvocationTargetException ite)
@@ -263,5 +274,9 @@ public class ASTIdentifier extends SimpleNode
log.error(msg, e);
throw new VelocityException(msg, e);
}
+ finally
+ {
+ context.remove("VELOCITY_STACK");
+ }
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@velocity.apache.org
For additional commands, e-mail: dev-h...@velocity.apache.org