001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.jexl2; 018 019 import org.apache.commons.jexl2.parser.JexlNode; 020 021 /** 022 * Wraps any error that might occur during interpretation of a script or expression. 023 * @since 2.0 024 */ 025 public class JexlException extends RuntimeException { 026 /** Serial version UID. */ 027 private static final long serialVersionUID = 2690666400232612395L; 028 /** The point of origin for this exception. */ 029 protected final JexlNode mark; 030 /** The debug info. */ 031 protected final JexlInfo info; 032 /** A marker to use in NPEs stating a null operand error. */ 033 public static final String NULL_OPERAND = "jexl.null"; 034 /** 035 * Creates a new JexlException. 036 * @param node the node causing the error 037 * @param msg the error message 038 */ 039 public JexlException(JexlNode node, String msg) { 040 super(msg); 041 mark = node; 042 info = node != null? node.getInfo() : null; 043 044 } 045 046 /** 047 * Creates a new JexlException. 048 * @param node the node causing the error 049 * @param msg the error message 050 * @param cause the exception causing the error 051 */ 052 public JexlException(JexlNode node, String msg, Throwable cause) { 053 super(msg, cause); 054 mark = node; 055 info = node != null? node.getInfo() : null; 056 } 057 058 /** 059 * Creates a new JexlException. 060 * @param dbg the debugging information associated 061 * @param msg the error message 062 */ 063 public JexlException(JexlInfo dbg, String msg) { 064 super(msg); 065 mark = null; 066 info = dbg; 067 } 068 069 /** 070 * Creates a new JexlException. 071 * @param dbg the debugging information associated 072 * @param msg the error message 073 * @param cause the exception causing the error 074 */ 075 public JexlException(JexlInfo dbg, String msg, Throwable cause) { 076 super(msg, cause); 077 mark = null; 078 info = dbg; 079 } 080 081 /** 082 * Gets information about the cause of this error. 083 * <p> 084 * The returned string represents the outermost expression in error. 085 * The info parameter, an int[2] optionally provided by the caller, will be filled with the begin/end offset 086 * characters of the precise error's trigger. 087 * </p> 088 * @param offsets character offset interval of the precise node triggering the error 089 * @return a string representation of the offending expression, the empty string if it could not be determined 090 */ 091 public String getInfo(int[] offsets) { 092 Debugger dbg = new Debugger(); 093 if (dbg.debug(mark)) { 094 if (offsets != null && offsets.length >= 2) { 095 offsets[0] = dbg.start(); 096 offsets[1] = dbg.end(); 097 } 098 return dbg.data(); 099 } 100 return ""; 101 } 102 103 /** 104 * Detailed info message about this error. 105 * Format is "debug![begin,end]: string \n msg" where: 106 * - debug is the debugging information if it exists (@link JexlEngine.setDebug) 107 * - begin, end are character offsets in the string for the precise location of the error 108 * - string is the string representation of the offending expression 109 * - msg is the actual explanation message for this error 110 * @return this error as a string 111 */ 112 @Override 113 public String getMessage() { 114 Debugger dbg = new Debugger(); 115 StringBuilder msg = new StringBuilder(); 116 if (info != null) { 117 msg.append(info.debugString()); 118 } 119 if (dbg.debug(mark)) { 120 msg.append("!["); 121 msg.append(dbg.start()); 122 msg.append(","); 123 msg.append(dbg.end()); 124 msg.append("]: '"); 125 msg.append(dbg.data()); 126 msg.append("'"); 127 } 128 msg.append(' '); 129 msg.append(super.getMessage()); 130 Throwable cause = getCause(); 131 if (cause != null && NULL_OPERAND == cause.getMessage()) { 132 msg.append(" caused by null operand"); 133 } 134 return msg.toString(); 135 } 136 }