You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2020/05/25 17:14:37 UTC

[myfaces] branch master updated: MYFACES-3258 Improve logging and exception handling for UILeaf

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/master by this push:
     new e91851e  MYFACES-3258 Improve logging and exception handling for UILeaf
e91851e is described below

commit e91851e60735aa88074c81c2e723d7fc80c3ea19
Author: Thomas Andraschko <ta...@apache.org>
AuthorDate: Mon May 25 19:14:30 2020 +0200

    MYFACES-3258 Improve logging and exception handling for UILeaf
---
 .../apache/myfaces/renderkit/ErrorPageWriter.java  |  6 +-
 .../view/facelets/compiler/CompilationManager.java | 23 +++++---
 .../view/facelets/compiler/SAXCompiler.java        | 38 ++++++-------
 .../myfaces/view/facelets/compiler/TextUnit.java   | 29 +++++-----
 .../facelets/compiler/UIInstructionHandler.java    |  2 +-
 .../el/ContextAwareTagValueExpression.java         | 57 ++++++++++---------
 .../apache/myfaces/view/facelets/el/ELText.java    | 65 ++++++++++++++++++----
 7 files changed, 138 insertions(+), 82 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java b/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java
index 0673c5a..03d31ce 100644
--- a/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/ErrorPageWriter.java
@@ -601,9 +601,9 @@ public final class ErrorPageWriter
             if (ex instanceof ContextAware)
             {
                 ContextAware caex = (ContextAware) ex;
-                contextAwareLocation = caex.getLocation().toString() + "    " +
-                                       caex.getQName() + "=\"" +
-                                       caex.getExpressionString() + '"';
+                contextAwareLocation = caex.getLocation().toString() + "    "
+                        + (caex.getQName() == null ? "" : (caex.getQName() + "=\""))
+                        + caex.getExpressionString() + '"';
             }
             if (ex.getMessage() != null)
             {
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/CompilationManager.java b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/CompilationManager.java
index 75a7fa0..7bd016c 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/CompilationManager.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/CompilationManager.java
@@ -25,6 +25,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import javax.faces.application.FacesMessage;
+import javax.faces.view.Location;
 import javax.faces.view.facelets.FaceletHandler;
 import javax.faces.view.facelets.Tag;
 import javax.faces.view.facelets.TagAttribute;
@@ -102,7 +103,7 @@ final class CompilationManager
         this.faceletsProcessingInstructions = instructions;
     }
 
-    public void writeInstruction(String value)
+    public void writeInstruction(String value, Location location)
     {
         if (this.finished)
         {
@@ -124,7 +125,8 @@ final class CompilationManager
         {
             unit = new TextUnit(this.alias, this.nextTagId(), 
                     faceletsProcessingInstructions.isEscapeInlineText(),
-                    faceletsProcessingInstructions.isCompressSpaces());
+                    faceletsProcessingInstructions.isCompressSpaces(),
+                    location);
             this.startUnit(unit);
         }
         unit.writeInstruction(value);
@@ -142,7 +144,7 @@ final class CompilationManager
         this.startUnit(unit);
     }
 
-    public void writeText(String value)
+    public void writeText(String value, Location location)
     {
 
         if (this.finished)
@@ -165,13 +167,14 @@ final class CompilationManager
         {
             unit = new TextUnit(this.alias, this.nextTagId(), 
                     faceletsProcessingInstructions.isEscapeInlineText(),
-                    faceletsProcessingInstructions.isCompressSpaces());
+                    faceletsProcessingInstructions.isCompressSpaces(),
+                    location);
             this.startUnit(unit);
         }
         unit.write(value);
     }
 
-    public void writeComment(String text)
+    public void writeComment(String text, Location location)
     {
         if (this.compiler.isTrimmingComments())
         {
@@ -198,18 +201,19 @@ final class CompilationManager
         {
             unit = new TextUnit(this.alias, this.nextTagId(), 
                     faceletsProcessingInstructions.isEscapeInlineText(),
-                    faceletsProcessingInstructions.isCompressSpaces());
+                    faceletsProcessingInstructions.isCompressSpaces(),
+                    location);
             this.startUnit(unit);
         }
 
         unit.writeComment(text);
     }
 
-    public void writeWhitespace(String text)
+    public void writeWhitespace(String text, Location location)
     {
         if (!this.compiler.isTrimmingWhitespace())
         {
-            this.writeText(text);
+            this.writeText(text, location);
         }
     }
 
@@ -310,7 +314,8 @@ final class CompilationManager
             {
                 unit = new TextUnit(this.alias, this.nextTagId(),
                         faceletsProcessingInstructions.isEscapeInlineText(),
-                        faceletsProcessingInstructions.isCompressSpaces());
+                        faceletsProcessingInstructions.isCompressSpaces(),
+                        orig.getLocation());
                 this.startUnit(unit);
             }
             
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/SAXCompiler.java b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/SAXCompiler.java
index 53d638b..79012d5 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/SAXCompiler.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/SAXCompiler.java
@@ -108,7 +108,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument && (!consumingCDATA || (consumingCDATA && !swallowCDATAContent)))
             {
-                this.unit.writeText(new String(ch, start, length));
+                this.unit.writeText(new String(ch, start, length), createLocation());
             }
         }
 
@@ -117,7 +117,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument && !unit.getFaceletsProcessingInstructions().isConsumeXMLComments())
             {
-                this.unit.writeComment(new String(ch, start, length));
+                this.unit.writeComment(new String(ch, start, length), createLocation());
             }
         }
 
@@ -145,7 +145,7 @@ public final class SAXCompiler extends Compiler
             {
                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
                 {
-                    this.unit.writeInstruction("]]>");
+                    this.unit.writeInstruction("]]>", createLocation());
                 }
                 else
                 {
@@ -196,7 +196,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument)
             {
-                this.unit.writeWhitespace(new String(ch, start, length));
+                this.unit.writeWhitespace(new String(ch, start, length), createLocation());
             }
         }
 
@@ -225,7 +225,7 @@ public final class SAXCompiler extends Compiler
             {
                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
                 {
-                    this.unit.writeInstruction("<![CDATA[");
+                    this.unit.writeInstruction("<![CDATA[", createLocation());
                 }
                 else
                 {
@@ -296,7 +296,7 @@ public final class SAXCompiler extends Compiler
             {
                 StringBuilder sb = new StringBuilder(64);
                 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
-                this.unit.writeInstruction(sb.toString());
+                this.unit.writeInstruction(sb.toString(), createLocation());
             }
         }
     }
@@ -334,7 +334,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument && inMetadata && (!consumingCDATA || (consumingCDATA && !swallowCDATAContent)))
             {
-                this.unit.writeText(new String(ch, start, length));
+                this.unit.writeText(new String(ch, start, length), createLocation());
             }
         }
 
@@ -343,7 +343,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument && inMetadata && !unit.getFaceletsProcessingInstructions().isConsumeXMLComments())
             {
-                this.unit.writeComment(new String(ch, start, length));
+                this.unit.writeComment(new String(ch, start, length), createLocation());
             }
         }
 
@@ -371,7 +371,7 @@ public final class SAXCompiler extends Compiler
             {
                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
                 {
-                    this.unit.writeInstruction("]]>");
+                    this.unit.writeInstruction("]]>", createLocation());
                 }
                 else
                 {
@@ -443,7 +443,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument && inMetadata)
             {
-                this.unit.writeWhitespace(new String(ch, start, length));
+                this.unit.writeWhitespace(new String(ch, start, length), createLocation());
             }
         }
 
@@ -472,7 +472,7 @@ public final class SAXCompiler extends Compiler
             {
                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
                 {
-                    this.unit.writeInstruction("<![CDATA[");
+                    this.unit.writeInstruction("<![CDATA[", createLocation());
                 }
                 else
                 {
@@ -542,7 +542,7 @@ public final class SAXCompiler extends Compiler
             {
                 StringBuilder sb = new StringBuilder(64);
                 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
-                unit.writeInstruction(sb.toString());
+                unit.writeInstruction(sb.toString(), createLocation());
             }
         }        
     }
@@ -585,7 +585,7 @@ public final class SAXCompiler extends Compiler
             if (this.inDocument && inCompositeInterface && 
                     (!consumingCDATA || (consumingCDATA && !swallowCDATAContent)))
             {
-                this.unit.writeText(new String(ch, start, length));
+                this.unit.writeText(new String(ch, start, length), createLocation());
             }
         }
 
@@ -595,7 +595,7 @@ public final class SAXCompiler extends Compiler
             if (inDocument && inCompositeInterface && 
                     !unit.getFaceletsProcessingInstructions().isConsumeXMLComments())
             {
-                this.unit.writeComment(new String(ch, start, length));
+                this.unit.writeComment(new String(ch, start, length), createLocation());
             }
         }
 
@@ -623,7 +623,7 @@ public final class SAXCompiler extends Compiler
             {
                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
                 {
-                    this.unit.writeInstruction("]]>");
+                    this.unit.writeInstruction("]]>", createLocation());
                 }
                 else
                 {
@@ -698,7 +698,7 @@ public final class SAXCompiler extends Compiler
         {
             if (this.inDocument && inCompositeInterface)
             {
-                this.unit.writeWhitespace(new String(ch, start, length));
+                this.unit.writeWhitespace(new String(ch, start, length), createLocation());
             }
         }
 
@@ -727,7 +727,7 @@ public final class SAXCompiler extends Compiler
             {
                 if (!this.unit.getFaceletsProcessingInstructions().isConsumeCDataSections())
                 {
-                    this.unit.writeInstruction("<![CDATA[");
+                    this.unit.writeInstruction("<![CDATA[", createLocation());
                 }
                 else
                 {
@@ -802,7 +802,7 @@ public final class SAXCompiler extends Compiler
             {
                 StringBuilder sb = new StringBuilder(64);
                 sb.append("<?").append(target).append(' ').append(data).append("?>\n");
-                this.unit.writeInstruction(sb.toString());
+                this.unit.writeInstruction(sb.toString(), createLocation());
             }
         }        
     }
@@ -1065,7 +1065,7 @@ public final class SAXCompiler extends Compiler
                 {
                     if (!mngr.getFaceletsProcessingInstructions().isConsumeXmlDeclaration())
                     {
-                        mngr.writeInstruction(m.group(0) + '\n');
+                        mngr.writeInstruction(m.group(0) + '\n', null);
                     }
                     if (m.group(3) != null)
                     {
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/TextUnit.java b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/TextUnit.java
index a25f200..34f8e80 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/TextUnit.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/TextUnit.java
@@ -25,6 +25,7 @@ import java.util.Stack;
 
 import javax.el.ELException;
 import javax.faces.application.FacesMessage;
+import javax.faces.view.Location;
 import javax.faces.view.facelets.CompositeFaceletHandler;
 import javax.faces.view.facelets.FaceletHandler;
 import javax.faces.view.facelets.Tag;
@@ -53,18 +54,19 @@ final class TextUnit extends CompilationUnit
     private final List<Object> messages;
     private final boolean escapeInlineText;
     private final boolean compressSpaces;
+    private final Location location;
 
-    public TextUnit(String alias, String id)
+    public TextUnit(String alias, String id, Location location)
     {
-        this(alias,id,true);
+        this(alias, id, true, location);
     }
     
-    public TextUnit(String alias, String id, boolean escapeInlineText)
+    public TextUnit(String alias, String id, boolean escapeInlineText, Location location)
     {
-        this(alias,id,escapeInlineText,false);
+        this(alias, id, escapeInlineText, false, location);
     }
     
-    public TextUnit(String alias, String id, boolean escapeInlineText, boolean compressSpaces)
+    public TextUnit(String alias, String id, boolean escapeInlineText, boolean compressSpaces, Location location)
     {
         this.alias = alias;
         this.id = id;
@@ -77,6 +79,7 @@ final class TextUnit extends CompilationUnit
         this.messages = new ArrayList<Object>(4);
         this.escapeInlineText = escapeInlineText;
         this.compressSpaces = compressSpaces;
+        this.location = location;
     }
 
     @Override
@@ -131,7 +134,7 @@ final class TextUnit extends CompilationUnit
                 if (!compressSpaces)
                 {
                     //Do it as usual.
-                    ELText txt = ELText.parse(s);
+                    ELText txt = ELText.parse(s, location);
                     if (txt != null)
                     {
                         if (txt.isLiteral())
@@ -155,7 +158,7 @@ final class TextUnit extends CompilationUnit
                             {
                                 // When escape inline text is disabled (jspx case) we have to split the EL and add
                                 // separate instructions, so it can be properly escaped.
-                                ELText[] splitText = ELText.parseAsArray(s);
+                                ELText[] splitText = ELText.parseAsArray(s, location);
                                 if (splitText.length > 1)
                                 {
                                     Instruction[] array = new Instruction[splitText.length];
@@ -207,7 +210,7 @@ final class TextUnit extends CompilationUnit
                             }
                             // When escape inline text is disabled (jspx case) we have to split the EL and add
                             // separate instructions, so it can be properly escaped.
-                            ELText[] splitText = ELText.parseAsArray(s);
+                            ELText[] splitText = ELText.parseAsArray(s, location);
                             if (splitText.length > 1)
                             {
                                 Instruction[] array = new Instruction[splitText.length];
@@ -227,7 +230,7 @@ final class TextUnit extends CompilationUnit
                             }
                             else
                             {
-                                this.instructionBuffer.add(new TextInstruction(this.alias, ELText.parse(s)));
+                                this.instructionBuffer.add(new TextInstruction(this.alias, ELText.parse(s, location)));
                             }
                         }
                     }
@@ -248,7 +251,7 @@ final class TextUnit extends CompilationUnit
     public void writeInstruction(String text)
     {
         this.finishStartTag();
-        ELText el = ELText.parse(text);
+        ELText el = ELText.parse(text, location);
         if (el.isLiteral())
         {
             this.addInstruction(new LiteralXMLInstruction(text));
@@ -264,7 +267,7 @@ final class TextUnit extends CompilationUnit
     {
         this.finishStartTag();
 
-        ELText el = ELText.parse(text);
+        ELText el = ELText.parse(text, location);
         if (el.isLiteral())
         {
             this.addInstruction(new LiteralCommentInstruction(text));
@@ -300,7 +303,7 @@ final class TextUnit extends CompilationUnit
                 String qname = attr.getQName();
                 String value = attr.getValue();
                 this.buffer.append(' ').append(qname).append("=\"").append(value).append('"');
-                ELText txt = ELText.parseAllowEmptyString(value);
+                ELText txt = ELText.parseAllowEmptyString(value, location);
                 if (txt != null)
                 {
                     if (txt.isLiteral())
@@ -387,7 +390,7 @@ final class TextUnit extends CompilationUnit
                 {
                     s = trimRight(s);
                 }
-                ELText txt = ELText.parse(s);
+                ELText txt = ELText.parse(s, location);
                 if (txt != null)
                 {
                     if (compressSpaces)
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UIInstructionHandler.java b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UIInstructionHandler.java
index 1e40649..17a29ef 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UIInstructionHandler.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/compiler/UIInstructionHandler.java
@@ -78,7 +78,7 @@ final class UIInstructionHandler extends AbstractUIHandler
         if (parent != null)
         {
             String facetName = this.getFacetName(ctx, parent);
-            
+
             // our id
             String id = ctx.generateUniqueId(this.id);
 
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/el/ContextAwareTagValueExpression.java b/impl/src/main/java/org/apache/myfaces/view/facelets/el/ContextAwareTagValueExpression.java
index 0aac882..bd775ff 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/el/ContextAwareTagValueExpression.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/el/ContextAwareTagValueExpression.java
@@ -46,26 +46,33 @@ public class ContextAwareTagValueExpression
 
     private static final long serialVersionUID = 1L;
 
-    private ValueExpression _wrapped; 
-    private Location _location;
-    private String _qName;
+    private ValueExpression wrapped; 
+    private Location location;
+    private String qName;
 
     public ContextAwareTagValueExpression()
     {
         super();
     }
 
+    public ContextAwareTagValueExpression(Location location, String qName, ValueExpression valueExpression)
+    {
+        this.location = location;
+        this.qName = qName;
+        this.wrapped = valueExpression;
+    }
+
     public ContextAwareTagValueExpression(TagAttribute tagAttribute, ValueExpression valueExpression)
     {
-        _location = tagAttribute.getLocation();
-        _qName = tagAttribute.getQName();
-        _wrapped = valueExpression;
+        this.location = tagAttribute.getLocation();
+        this.qName = tagAttribute.getQName();
+        this.wrapped = valueExpression;
     }
 
     @Override
     public Class<?> getExpectedType()
     {
-        return _wrapped.getExpectedType();
+        return wrapped.getExpectedType();
     }
 
     @Override
@@ -73,7 +80,7 @@ public class ContextAwareTagValueExpression
     {
         try
         {
-            return _wrapped.getType(context);
+            return wrapped.getType(context);
         }
         catch (PropertyNotFoundException pnfe)
         {
@@ -90,7 +97,7 @@ public class ContextAwareTagValueExpression
     {
         try
         {
-            return _wrapped.getValue(context);
+            return wrapped.getValue(context);
         }
         catch (PropertyNotFoundException pnfe)
         {
@@ -126,7 +133,7 @@ public class ContextAwareTagValueExpression
     {
         try
         {
-            return _wrapped.isReadOnly(context);
+            return wrapped.isReadOnly(context);
         }
         catch (PropertyNotFoundException pnfe)
         {
@@ -143,7 +150,7 @@ public class ContextAwareTagValueExpression
     {
         try
         {
-            _wrapped.setValue(context, value);
+            wrapped.setValue(context, value);
         }
         catch (PropertyNotFoundException pnfe)
         {
@@ -163,65 +170,65 @@ public class ContextAwareTagValueExpression
     @Override
     public boolean equals(Object obj)
     {
-        return _wrapped.equals(obj);
+        return wrapped.equals(obj);
     }
 
     @Override
     public String getExpressionString()
     {
-        return _wrapped.getExpressionString();
+        return wrapped.getExpressionString();
     }
 
     @Override
     public int hashCode()
     {
-        return _wrapped.hashCode();
+        return wrapped.hashCode();
     }
 
     @Override
     public boolean isLiteralText()
     {
-        return _wrapped.isLiteralText();
+        return wrapped.isLiteralText();
     }
 
     @Override
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
     {
-        _wrapped = (ValueExpression) in.readObject();
-        _location = (Location) in.readObject();
-        _qName = in.readUTF();
+        wrapped = (ValueExpression) in.readObject();
+        location = (Location) in.readObject();
+        qName = in.readUTF();
     }
 
     @Override
     public void writeExternal(ObjectOutput out) throws IOException
     {
-        out.writeObject(_wrapped);
-        out.writeObject(_location);
-        out.writeUTF(_qName);
+        out.writeObject(wrapped);
+        out.writeObject(location);
+        out.writeUTF(qName);
     }
 
     @Override
     public String toString()
     {
-        return _location + ": " + _wrapped;
+        return location + ": " + wrapped;
     }
 
     @Override
     public ValueExpression getWrapped()
     {
-        return _wrapped;
+        return wrapped;
     }
 
     @Override
     public Location getLocation()
     {
-        return _location;
+        return location;
     }
     
     @Override
     public String getQName()
     {
-        return _qName;
+        return qName;
     }
     
     @Override
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/el/ELText.java b/impl/src/main/java/org/apache/myfaces/view/facelets/el/ELText.java
index c3d5c8f..2600084 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/el/ELText.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/el/ELText.java
@@ -287,11 +287,11 @@ public class ELText
                         Location location = (Location) cc.getAttributes().get(CompositeComponentELUtils.LOCATION_KEY);
                         if (location != null)
                         {
-                            return new ELTextVariable(((LocationValueExpression)cached.ve).apply(
+                            return new ELTextVariable(((LocationValueExpression) cached.ve).apply(
                                     actx.getFaceletCompositionContext().getCompositeComponentLevel(), location));
                         }
                     }
-                    return new ELTextVariable(((LocationValueExpression)cached.ve).apply(
+                    return new ELTextVariable(((LocationValueExpression) cached.ve).apply(
                             actx.getFaceletCompositionContext().getCompositeComponentLevel()));
                 }
                 return cached;
@@ -303,6 +303,14 @@ public class ELText
                 ValueExpression valueExpression
                         = factory.createValueExpression(ctx, this.ve.getExpressionString(), String.class);
               
+                if (this.ve instanceof ContextAwareTagValueExpression)
+                {
+                    valueExpression = new ContextAwareTagValueExpression(
+                            ((ContextAwareTagValueExpression) this.ve).getLocation(),
+                            "expression",
+                            valueExpression);
+                }
+
                 if ((this.capabilities & EL_CC) != 0)
                 {
                     UIComponent cc = actx.getFaceletCompositionContext().getCompositeComponentFromStack();
@@ -458,21 +466,28 @@ public class ELText
         return isLiteral(null, null, in);
     }
 
+    public static ELText parse(String in) throws ELException
+    {
+        return parse(null, null, in, null);
+    }
+
     /**
      * Factory method for creating an unvalidated ELText instance. NOTE: All expressions in the passed String are
      * treated as {@link org.apache.myfaces.view.facelets.el.LocationValueExpression}.
      * 
      * @param in
      *            String to parse
+     * @param location
+     *            The location
      * @return ELText instance that knows if the String was literal or not
      * @throws javax.el.ELException
      */
-    public static ELText parse(String in) throws ELException
+    public static ELText parse(String in, Location location) throws ELException
     {
-        return parse(null, null, in);
+        return parse(null, null, in, location);
     }
     
-    public static ELText parseAllowEmptyString(String in) throws ELException
+    public static ELText parseAllowEmptyString(String in, Location location) throws ELException
     {
         if (in != null && in.length() == 0)
         {
@@ -480,10 +495,15 @@ public class ELText
         }
         else
         {
-            return parse(null, null, in);
+            return parse(null, null, in, location);
         }
     }
 
+    public static ELText parse(ExpressionFactory fact, ELContext ctx, String in) throws ELException
+    {
+        return parse(fact, ctx, in, null);
+    }
+
     /**
      * Factory method for creating a validated ELText instance. When an Expression is hit, it will use the
      * ExpressionFactory to create a ValueExpression instance, resolving any functions at that time. <p> Variables and
@@ -495,10 +515,12 @@ public class ELText
      *            ELContext to validate against
      * @param in
      *            String to parse
+     * @param location
+     *            The location
      * @return ELText that can be re-applied later
      * @throws javax.el.ELException
      */
-    public static ELText parse(ExpressionFactory fact, ELContext ctx, String in) throws ELException
+    public static ELText parse(ExpressionFactory fact, ELContext ctx, String in, Location location) throws ELException
     {
         char[] ca = in.toCharArray();
         int i = 0;
@@ -540,11 +562,20 @@ public class ELText
                         if (ctx != null && fact != null)
                         {
                             ve = fact.createValueExpression(ctx, new String(ca, i, vlen), String.class);
+                            if (location != null)
+                            {
+                                ve = new ContextAwareTagValueExpression(location, "expression", ve);
+                            }
                             t = new ELCacheableTextVariable(ve);
                         }
                         else
                         {
-                            t = new ELCacheableTextVariable(new LiteralValueExpression(new String(ca, i, vlen)));
+                            ve = new LiteralValueExpression(new String(ca, i, vlen));
+                            if (location != null)
+                            {
+                                ve = new ContextAwareTagValueExpression(location, "expression", ve);
+                            }
+                            t = new ELCacheableTextVariable(ve);
                         }
                         text.add(t);
                         i += vlen;
@@ -578,12 +609,13 @@ public class ELText
         }
     }
 
-    public static ELText[] parseAsArray(String in) throws ELException
+    public static ELText[] parseAsArray(String in, Location location) throws ELException
     {
-        return parseAsArray(null, null, in);
+        return parseAsArray(null, null, in, location);
     }
     
-    public static ELText[] parseAsArray(ExpressionFactory fact, ELContext ctx, String in) throws ELException
+    public static ELText[] parseAsArray(ExpressionFactory fact, ELContext ctx, String in, Location location)
+            throws ELException
     {
         char[] ca = in.toCharArray();
         int i = 0;
@@ -625,11 +657,20 @@ public class ELText
                         if (ctx != null && fact != null)
                         {
                             ve = fact.createValueExpression(ctx, new String(ca, i, vlen), String.class);
+                            if (location != null)
+                            {
+                                ve = new ContextAwareTagValueExpression(location, "expression", ve);
+                            }
                             t = new ELCacheableTextVariable(ve);
                         }
                         else
                         {
-                            t = new ELCacheableTextVariable(new LiteralValueExpression(new String(ca, i, vlen)));
+                            ve = new LiteralValueExpression(new String(ca, i, vlen));
+                            if (location != null)
+                            {
+                                ve = new ContextAwareTagValueExpression(location, "expression", ve);
+                            }
+                            t = new ELCacheableTextVariable(ve);
                         }
                         text.add(t);
                         i += vlen;