Mon, 05 Jan 2015 16:02:56 +0530
8068431: @since and @jdk.Exported are missing in jdk.nashorn.api.scripting classes and package-info.java files
Reviewed-by: attila, lagergren
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package jdk.nashorn.api.scripting;
28 import java.util.ArrayList;
29 import java.util.List;
30 import jdk.nashorn.internal.codegen.CompilerConstants;
31 import jdk.nashorn.internal.runtime.ECMAErrors;
32 import jdk.nashorn.internal.runtime.ScriptObject;
34 /**
35 * This is base exception for all Nashorn exceptions. These originate from
36 * user's ECMAScript code. Example: script parse errors, exceptions thrown from
37 * scripts. Note that ScriptEngine methods like "eval", "invokeMethod",
38 * "invokeFunction" will wrap this as ScriptException and throw it. But, there
39 * are cases where user may need to access this exception (or implementation
40 * defined subtype of this). For example, if java interface is implemented by a
41 * script object or Java access to script object properties via java.util.Map
42 * interface. In these cases, user code will get an instance of this or
43 * implementation defined subclass.
44 *
45 * @since 1.8u40
46 */
47 @jdk.Exported
48 @SuppressWarnings("serial")
49 public abstract class NashornException extends RuntimeException {
50 // script file name
51 private String fileName;
52 // script line number
53 private int line;
54 // script column number
55 private int column;
56 // underlying ECMA error object - lazily initialized
57 private Object ecmaError;
59 /**
60 * Constructor
61 *
62 * @param msg exception message
63 * @param fileName file name
64 * @param line line number
65 * @param column column number
66 */
67 protected NashornException(final String msg, final String fileName, final int line, final int column) {
68 this(msg, null, fileName, line, column);
69 }
71 /**
72 * Constructor
73 *
74 * @param msg exception message
75 * @param cause exception cause
76 * @param fileName file name
77 * @param line line number
78 * @param column column number
79 */
80 protected NashornException(final String msg, final Throwable cause, final String fileName, final int line, final int column) {
81 super(msg, cause == null ? null : cause);
82 this.fileName = fileName;
83 this.line = line;
84 this.column = column;
85 }
87 /**
88 * Constructor
89 *
90 * @param msg exception message
91 * @param cause exception cause
92 */
93 protected NashornException(final String msg, final Throwable cause) {
94 super(msg, cause == null ? null : cause);
95 // This is not so pretty - but it gets the job done. Note that the stack
96 // trace has been already filled by "fillInStackTrace" call from
97 // Throwable
98 // constructor and so we don't pay additional cost for it.
100 // Hard luck - no column number info
101 this.column = -1;
103 // Find the first JavaScript frame by walking and set file, line from it
104 // Usually, we should be able to find it in just few frames depth.
105 for (final StackTraceElement ste : getStackTrace()) {
106 if (ECMAErrors.isScriptFrame(ste)) {
107 // Whatever here is compiled from JavaScript code
108 this.fileName = ste.getFileName();
109 this.line = ste.getLineNumber();
110 return;
111 }
112 }
114 this.fileName = null;
115 this.line = 0;
116 }
118 /**
119 * Get the source file name for this {@code NashornException}
120 *
121 * @return the file name
122 */
123 public final String getFileName() {
124 return fileName;
125 }
127 /**
128 * Set the source file name for this {@code NashornException}
129 *
130 * @param fileName the file name
131 */
132 public final void setFileName(final String fileName) {
133 this.fileName = fileName;
134 }
136 /**
137 * Get the line number for this {@code NashornException}
138 *
139 * @return the line number
140 */
141 public final int getLineNumber() {
142 return line;
143 }
145 /**
146 * Set the line number for this {@code NashornException}
147 *
148 * @param line the line number
149 */
150 public final void setLineNumber(final int line) {
151 this.line = line;
152 }
154 /**
155 * Get the column for this {@code NashornException}
156 *
157 * @return the column number
158 */
159 public final int getColumnNumber() {
160 return column;
161 }
163 /**
164 * Set the column for this {@code NashornException}
165 *
166 * @param column the column number
167 */
168 public final void setColumnNumber(final int column) {
169 this.column = column;
170 }
172 /**
173 * Returns array javascript stack frames from the given exception object.
174 *
175 * @param exception exception from which stack frames are retrieved and filtered
176 * @return array of javascript stack frames
177 */
178 public static StackTraceElement[] getScriptFrames(final Throwable exception) {
179 final StackTraceElement[] frames = exception.getStackTrace();
180 final List<StackTraceElement> filtered = new ArrayList<>();
181 for (final StackTraceElement st : frames) {
182 if (ECMAErrors.isScriptFrame(st)) {
183 final String className = "<" + st.getFileName() + ">";
184 String methodName = st.getMethodName();
185 if (methodName.equals(CompilerConstants.PROGRAM.symbolName())) {
186 methodName = "<program>";
187 }
189 if (methodName.contains(CompilerConstants.ANON_FUNCTION_PREFIX.symbolName())) {
190 methodName = "<anonymous>";
191 }
193 filtered.add(new StackTraceElement(className, methodName,
194 st.getFileName(), st.getLineNumber()));
195 }
196 }
197 return filtered.toArray(new StackTraceElement[filtered.size()]);
198 }
200 /**
201 * Return a formatted script stack trace string with frames information separated by '\n'
202 *
203 * @param exception exception for which script stack string is returned
204 * @return formatted stack trace string
205 */
206 public static String getScriptStackString(final Throwable exception) {
207 final StringBuilder buf = new StringBuilder();
208 final StackTraceElement[] frames = getScriptFrames(exception);
209 for (final StackTraceElement st : frames) {
210 buf.append("\tat ");
211 buf.append(st.getMethodName());
212 buf.append(" (");
213 buf.append(st.getFileName());
214 buf.append(':');
215 buf.append(st.getLineNumber());
216 buf.append(")\n");
217 }
218 final int len = buf.length();
219 // remove trailing '\n'
220 if (len > 0) {
221 assert buf.charAt(len - 1) == '\n';
222 buf.deleteCharAt(len - 1);
223 }
224 return buf.toString();
225 }
227 /**
228 * Get the thrown object. Subclass responsibility
229 * @return thrown object
230 */
231 protected Object getThrown() {
232 return null;
233 }
235 /**
236 * Initialization function for ECMA errors. Stores the error
237 * in the ecmaError field of this class. It is only initialized
238 * once, and then reused
239 *
240 * @param global the global
241 * @return initialized exception
242 */
243 protected NashornException initEcmaError(final ScriptObject global) {
244 if (ecmaError != null) {
245 return this; // initialized already!
246 }
248 final Object thrown = getThrown();
249 if (thrown instanceof ScriptObject) {
250 setEcmaError(ScriptObjectMirror.wrap(thrown, global));
251 } else {
252 setEcmaError(thrown);
253 }
255 return this;
256 }
258 /**
259 * Return the underlying ECMA error object, if available.
260 *
261 * @return underlying ECMA Error object's mirror or whatever was thrown
262 * from script such as a String, Number or a Boolean.
263 */
264 public Object getEcmaError() {
265 return ecmaError;
266 }
268 /**
269 * Return the underlying ECMA error object, if available.
270 *
271 * @param ecmaError underlying ECMA Error object's mirror or whatever was thrown
272 * from script such as a String, Number or a Boolean.
273 */
274 public void setEcmaError(final Object ecmaError) {
275 this.ecmaError = ecmaError;
276 }
277 }