src/jdk/nashorn/api/scripting/NashornException.java

Thu, 12 Oct 2017 19:52:15 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:52:15 +0800
changeset 1205
4112748288bb
parent 963
e2497b11a021
parent 952
6d5471a497fb
child 1490
d85f981c8cf8
permissions
-rw-r--r--

merge

     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 @SuppressWarnings("serial")
    46 public abstract class NashornException extends RuntimeException {
    47     // script file name
    48     private String fileName;
    49     // script line number
    50     private int line;
    51     // script column number
    52     private int column;
    53     // underlying ECMA error object - lazily initialized
    54     private Object ecmaError;
    56     /**
    57      * Constructor
    58      *
    59      * @param msg       exception message
    60      * @param fileName  file name
    61      * @param line      line number
    62      * @param column    column number
    63      */
    64     protected NashornException(final String msg, final String fileName, final int line, final int column) {
    65         this(msg, null, fileName, line, column);
    66     }
    68     /**
    69      * Constructor
    70      *
    71      * @param msg       exception message
    72      * @param cause     exception cause
    73      * @param fileName  file name
    74      * @param line      line number
    75      * @param column    column number
    76      */
    77     protected NashornException(final String msg, final Throwable cause, final String fileName, final int line, final int column) {
    78         super(msg, cause == null ? null : cause);
    79         this.fileName = fileName;
    80         this.line = line;
    81         this.column = column;
    82     }
    84     /**
    85      * Constructor
    86      *
    87      * @param msg       exception message
    88      * @param cause     exception cause
    89      */
    90     protected NashornException(final String msg, final Throwable cause) {
    91         super(msg, cause == null ? null : cause);
    92         // This is not so pretty - but it gets the job done. Note that the stack
    93         // trace has been already filled by "fillInStackTrace" call from
    94         // Throwable
    95         // constructor and so we don't pay additional cost for it.
    97         // Hard luck - no column number info
    98         this.column = -1;
   100         // Find the first JavaScript frame by walking and set file, line from it
   101         // Usually, we should be able to find it in just few frames depth.
   102         for (final StackTraceElement ste : getStackTrace()) {
   103             if (ECMAErrors.isScriptFrame(ste)) {
   104                 // Whatever here is compiled from JavaScript code
   105                 this.fileName = ste.getFileName();
   106                 this.line = ste.getLineNumber();
   107                 return;
   108             }
   109         }
   111         this.fileName = null;
   112         this.line = 0;
   113     }
   115     /**
   116      * Get the source file name for this {@code NashornException}
   117      *
   118      * @return the file name
   119      */
   120     public final String getFileName() {
   121         return fileName;
   122     }
   124     /**
   125      * Set the source file name for this {@code NashornException}
   126      *
   127      * @param fileName the file name
   128      */
   129     public final void setFileName(final String fileName) {
   130         this.fileName = fileName;
   131     }
   133     /**
   134      * Get the line number for this {@code NashornException}
   135      *
   136      * @return the line number
   137      */
   138     public final int getLineNumber() {
   139         return line;
   140     }
   142     /**
   143      * Set the line number for this {@code NashornException}
   144      *
   145      * @param line the line number
   146      */
   147     public final void setLineNumber(final int line) {
   148         this.line = line;
   149     }
   151     /**
   152      * Get the column for this {@code NashornException}
   153      *
   154      * @return the column number
   155      */
   156     public final int getColumnNumber() {
   157         return column;
   158     }
   160     /**
   161      * Set the column for this {@code NashornException}
   162      *
   163      * @param column the column number
   164      */
   165     public final void setColumnNumber(final int column) {
   166         this.column = column;
   167     }
   169     /**
   170      * Returns array javascript stack frames from the given exception object.
   171      *
   172      * @param exception exception from which stack frames are retrieved and filtered
   173      * @return array of javascript stack frames
   174      */
   175     public static StackTraceElement[] getScriptFrames(final Throwable exception) {
   176         final StackTraceElement[] frames = exception.getStackTrace();
   177         final List<StackTraceElement> filtered = new ArrayList<>();
   178         for (final StackTraceElement st : frames) {
   179             if (ECMAErrors.isScriptFrame(st)) {
   180                 final String className = "<" + st.getFileName() + ">";
   181                 String methodName = st.getMethodName();
   182                 if (methodName.equals(CompilerConstants.PROGRAM.symbolName())) {
   183                     methodName = "<program>";
   184                 }
   186                 if (methodName.contains(CompilerConstants.ANON_FUNCTION_PREFIX.symbolName())) {
   187                     methodName = "<anonymous>";
   188                 }
   190                 filtered.add(new StackTraceElement(className, methodName,
   191                         st.getFileName(), st.getLineNumber()));
   192             }
   193         }
   194         return filtered.toArray(new StackTraceElement[filtered.size()]);
   195     }
   197     /**
   198      * Return a formatted script stack trace string with frames information separated by '\n'
   199      *
   200      * @param exception exception for which script stack string is returned
   201      * @return formatted stack trace string
   202      */
   203     public static String getScriptStackString(final Throwable exception) {
   204         final StringBuilder buf = new StringBuilder();
   205         final StackTraceElement[] frames = getScriptFrames(exception);
   206         for (final StackTraceElement st : frames) {
   207             buf.append("\tat ");
   208             buf.append(st.getMethodName());
   209             buf.append(" (");
   210             buf.append(st.getFileName());
   211             buf.append(':');
   212             buf.append(st.getLineNumber());
   213             buf.append(")\n");
   214         }
   215         final int len = buf.length();
   216         // remove trailing '\n'
   217         if (len > 0) {
   218             assert buf.charAt(len - 1) == '\n';
   219             buf.deleteCharAt(len - 1);
   220         }
   221         return buf.toString();
   222     }
   224     /**
   225      * Get the thrown object. Subclass responsibility
   226      * @return thrown object
   227      */
   228     protected Object getThrown() {
   229         return null;
   230     }
   232     /**
   233      * Initialization function for ECMA errors. Stores the error
   234      * in the ecmaError field of this class. It is only initialized
   235      * once, and then reused
   236      *
   237      * @param global the global
   238      * @return initialized exception
   239      */
   240     protected NashornException initEcmaError(final ScriptObject global) {
   241         if (ecmaError != null) {
   242             return this; // initialized already!
   243         }
   245         final Object thrown = getThrown();
   246         if (thrown instanceof ScriptObject) {
   247             setEcmaError(ScriptObjectMirror.wrap(thrown, global));
   248         } else {
   249             setEcmaError(thrown);
   250         }
   252         return this;
   253     }
   255     /**
   256      * Return the underlying ECMA error object, if available.
   257      *
   258      * @return underlying ECMA Error object's mirror or whatever was thrown
   259      *         from script such as a String, Number or a Boolean.
   260      */
   261     public Object getEcmaError() {
   262         return ecmaError;
   263     }
   265     /**
   266      * Return the underlying ECMA error object, if available.
   267      *
   268      * @param ecmaError underlying ECMA Error object's mirror or whatever was thrown
   269      *         from script such as a String, Number or a Boolean.
   270      */
   271     public void setEcmaError(final Object ecmaError) {
   272         this.ecmaError = ecmaError;
   273     }
   274 }

mercurial