public String toString()

in freemarker-core/src/main/java/freemarker/core/_ErrorDescriptionBuilder.java [71:168]


    public String toString(TemplateElement parentElement, boolean showTips) {
        if (blamed == null && tips == null && tip == null && descriptionParts == null) return description;

        StringBuilder sb = new StringBuilder(200);
        
        if (parentElement != null && blamed != null && showBlamer) {
            try {
                Blaming blaming = findBlaming(parentElement, blamed, 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.
                LOG.error("Error when searching blamer for better error message.", e);
            }
        }
        
        if (description != null) {
            sb.append(description);
        } else {
            appendParts(sb, descriptionParts);
        }

        String extraTip = null;
        if (blamed != 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(blamed.toString());
            for (int i = 0; i < lines.length; i++) {
                sb.append(i == 0 ? "==> " : "\n    ");
                sb.append(lines[i]);
            }
            
            sb.append("  [");
            sb.append(blamed.getStartLocation());
            sb.append(']');
            
            
            if (containsSingleInterpolatoinLiteral(blamed, 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 = (tips != null ? tips.length : 0) + (tip != null ? 1 : 0) + (extraTip != null ? 1 : 0);
            Object[] allTips;
            if (tips != null && allTipsLen == tips.length) {
                allTips = tips;
            } else {
                allTips = new Object[allTipsLen];
                int dst = 0;
                if (tip != null) allTips[dst++] = tip; 
                if (tips != null) {
                    for (int i = 0; i < tips.length; i++) {
                        allTips[dst++] = tips[i]; 
                    }
                }
                if (extraTip != null) allTips[dst++] = extraTip; 
            }
            if (allTips != null && allTips.length > 0) {
                sb.append("\n\n");
                for (int i = 0; i < allTips.length; i++) {
                    if (i != 0) sb.append('\n');
                    sb.append(_CoreAPI.ERROR_MESSAGE_HR).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(_CoreAPI.ERROR_MESSAGE_HR);
            }
        }
        
        return sb.toString();
    }