Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2014 Attila Szegedi, Daniel Dekany, Jonathan Revusky
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   * http://www.apache.org/licenses/LICENSE-2.0
   * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package freemarker.core;
 
 
Used internally only, might changes without notice! Packs a structured from of the error description from which the error message can be rendered on-demand. Note that this class isn't serializable, thus the containing exception should render the message before it's serialized.
 
 public class _ErrorDescriptionBuilder {
 
     private static final Logger LOG = Logger.getLogger("freemarker.runtime");
 
     private final String description;
     private final Object[] descriptionParts;
     private Expression blamed;
     private boolean showBlamer;
     private Object/*String|Object[]*/ tip;
     private Object[]/*String[]|Object[][]*/ tips;
     private Template template;
 
     public _ErrorDescriptionBuilder(String description) {
         this. = description;
         this. = null;
     }

    

Parameters:
descriptionParts These will be concatenated to a single java.lang.String in toString(). java.lang.String array items that look like FTL tag (must start with "<" and end with ">") will be converted to the actual template syntax if blamed or template was set.
 
     public _ErrorDescriptionBuilder(Object[] descriptionParts) {
         this. = descriptionParts;
         this. = null;
     }
 
     public String toString() {
         return toString(nulltrue);
     }
     
     public String toString(TemplateElement parentElementboolean showTips) {
         if ( == null &&  == null &&  == null &&  == nullreturn ;
 
         StringBuffer sb = new StringBuffer(200);
         
         if (parentElement != null &&  != null && ) {
             try {
                 Blaming blaming = findBlaming(parentElement, 0);
                 if (blaming != null) {
                     sb.append("For ");
                     String nss = blaming.blamer.getNodeTypeSymbol();
                     char q = nss.indexOf('"') == -1 ? '\"' : '`';
                     sb.append(q).append(nss).append(q);
                     sb.append(" ").append(blaming.roleOfblamed).append(": ");
                 }
             } catch (Throwable e) {
                 // Should not happen. But we rather give a not-so-good error message than replace it with another...
                 // So we ignore this.
                 .error("Error when searching blamer for better error message."e);
             }
         }
         
         if ( != null) {
             sb.append();
         } else {
             appendParts(sb);
         }
 
         String extraTip = null;
         if ( != null) {
             // Right-trim:
             for (int idx = sb.length() - 1; idx >= 0 && Character.isWhitespace(sb.charAt(idx)); idx --) {
                 sb.deleteCharAt(idx);
            }
            
            char lastChar = sb.length() > 0 ? (sb.charAt(sb.length() - 1)) : 0;
            if (lastChar != 0) {
                sb.append('\n');
            }
            if (lastChar != ':') {
                sb.append("The blamed expression:\n");
            }
            
            String[] lines = splitToLines(.toString());
            for (int i = 0; i < lines.lengthi++) {
                sb.append(i == 0 ? "==> " : "\n    ");
                sb.append(lines[i]);
            }
            
            sb.append("  [");
            sb.append(.getStartLocation());
            sb.append(']');
            
            
            if (containsSingleInterpolatoinLiteral(, 0)) {
                extraTip = "It has been noticed that you are using ${...} as the sole content of a quoted string. That "
                        + "does nothing but forcably converts the value inside ${...} to string (as it inserts it into "
                        + "the enclosing string). "
                        + "If that's not what you meant, just remove the quotation marks, ${ and }; you don't need "
                        + "them. If you indeed wanted to convert to string, use myExpression?string instead.";
            }
        }
        
        if (showTips) {
            int allTipsLen = ( != null ? . : 0) + ( != null ? 1 : 0) + (extraTip != null ? 1 : 0);
            Object[] allTips;
            if ( != null && allTipsLen == .) {
                allTips = ;
            } else {
                allTips = new Object[allTipsLen];
                int dst = 0;
                if ( != nullallTips[dst++] = 
                if ( != null) {
                    for (int i = 0; i < .i++) {
                        allTips[dst++] = [i]; 
                    }
                }
                if (extraTip != nullallTips[dst++] = extraTip
            }
            if (allTips != null && allTips.length > 0) {
                sb.append("\n\n");
                for (int i = 0; i < allTips.lengthi++) {
                    if (i != 0) sb.append('\n');
                    sb.append(.).append('\n');
                    sb.append("Tip: ");
                    Object tip = allTips[i];
                    if (!(tip instanceof Object[])) {
                        sb.append(allTips[i]);
                    } else {
                        appendParts(sb, (Object[]) tip);
                    }
                }
                sb.append('\n').append(.);
            }
        }
        
        return sb.toString();
    }
    private boolean containsSingleInterpolatoinLiteral(Expression expint recursionDepth) {
        if (exp == nullreturn false;
        
        // Just in case a loop ever gets into the AST somehow, try not fill the stack and such: 
        if (recursionDepth > 20) return false;
        
        if (exp instanceof StringLiteral && ((StringLiteralexp).isSingleInterpolationLiteral()) return true;
        
        int paramCnt = exp.getParameterCount();
        for (int i = 0; i < paramCnti++) {
            Object paramValue = exp.getParameterValue(i);
            if (paramValue instanceof Expression) {
                boolean result = containsSingleInterpolatoinLiteral((ExpressionparamValuerecursionDepth + 1);
                if (resultreturn true;
            }
        }
        
        return false;
    }
    private Blaming findBlaming(TemplateObject parentExpression blamedint recursionDepth) {
        // Just in case a loop ever gets into the AST somehow, try not fill the stack and such: 
        if (recursionDepth > 50) return null;
        
        int paramCnt = parent.getParameterCount();
        for (int i = 0; i < paramCnti++) {
            Object paramValue = parent.getParameterValue(i);
            if (paramValue == blamed) {
                Blaming blaming = new Blaming();
                blaming.blamer = parent;
                blaming.roleOfblamed = parent.getParameterRole(i);
                return blaming;
            } else if (paramValue instanceof TemplateObject) {
                Blaming blaming = findBlaming((TemplateObjectparamValueblamedrecursionDepth + 1);
                if (blaming != nullreturn blaming;
            }
        }
        return null;
    }
    private void appendParts(StringBuffer sbObject[] parts) {
        Template template = this. != null ? this. : ( != null ? .getTemplate() : null); 
        for (int i = 0; i < parts.lengthi++) {
            Object partObj = parts[i];
            if (partObj instanceof Object[]) {
                appendParts(sb, (Object[]) partObj);
            } else {
                String partStr;
                partStr = tryToString(partObj);
                if (partStr == null) {
                    partStr = "null";
                }
                
                if (template != null) {
                    if (partStr.length() > 4
                            && partStr.charAt(0) == '<'
                            && (
                                    (partStr.charAt(1) == '#' || partStr.charAt(1) == '@')
                                    || (partStr.charAt(1) == '/') && (partStr.charAt(2) == '#' || partStr.charAt(2) == '@')
                               )
                            && partStr.charAt(partStr.length() - 1) == '>') {
                        if (template.getActualTagSyntax() == .) {
                            sb.append('[');
                            sb.append(partStr.substring(1, partStr.length() - 1));
                            sb.append(']');
                        } else {
                            sb.append(partStr);
                        }
                    } else {
                        sb.append(partStr);
                    }
                } else {
                    sb.append(partStr);
                }
            }
        }
    }

    
A twist on Java's toString that generates more appropriate results for generating error messages.
    public static String toString(Object partObj) {
        return toString(partObjfalse);
    }
    public static String tryToString(Object partObj) {
        return toString(partObjtrue);
    }
    
    private static String toString(Object partObjboolean suppressToStringException) {
        final String partStr;
        if (partObj == null) {
            return null;
        } else if (partObj instanceof Class) {
            partStr = ClassUtil.getShortClassName((ClasspartObj);
        } else if (partObj instanceof Method || partObj instanceof Constructor) {
            partStr = _MethodUtil.toString((MemberpartObj);
        } else {
            partStr = suppressToStringException ? StringUtil.tryToString(partObj) : partObj.toString();
        }
        return partStr;
    }
    private String[] splitToLines(String s) {
        s = StringUtil.replace(s"\r\n""\n");
        s = StringUtil.replace(s"\r""\n");
        String[] lines = StringUtil.split(s'\n');
        return lines;
    }
    
    
Needed for description parts that look like an FTL tag to be converted, if there's no blamed.
    public _ErrorDescriptionBuilder template(Template template) {
        this. = template;
        return this;
    }
    public _ErrorDescriptionBuilder blame(Expression blamedExpr) {
        this. = blamedExpr;
        return this;
    }
    
    public _ErrorDescriptionBuilder showBlamer(boolean showBlamer) {
        this. = showBlamer;
        return this;
    }
    
    public _ErrorDescriptionBuilder tip(String tip) {
        tip((Objecttip);
        return this;
    }
    
    public _ErrorDescriptionBuilder tip(Object tip[]) {
        tip((Objecttip);
        return this;
    }
    
    private _ErrorDescriptionBuilder tip(Object tip) {
        if (this. == null) {
            this. = tip;
        } else {
            if ( == null) {
                 = new Object[] { tip };
            } else {
                final int origTipsLen = .;
                
                Object[] newTips = new Object[origTipsLen + 1];
                for (int i = 0; i < origTipsLeni++) {
                    newTips[i] = [i];
                }
                newTips[origTipsLen] = tip;
                 = newTips;
            }
        }
        return this;
    }
    
    public _ErrorDescriptionBuilder tips(Object[] tips) {
        if (this. == null) {
            this. = tips;
        } else {
            final int origTipsLen = this..length;
            final int additionalTipsLen = tips.length;
            
            Object[] newTips = new Object[origTipsLen + additionalTipsLen];
            for (int i = 0; i < origTipsLeni++) {
                newTips[i] = this.[i];
            }
            for (int i = 0; i < additionalTipsLeni++) {
                newTips[origTipsLen + i] = tips[i];
            }
            this. = newTips;
        }
        return this;
    }
    
    private static class Blaming {
        TemplateObject blamer;
        ParameterRole roleOfblamed;
    }
    
New to GrepCode? Check out our FAQ X