Exception的ToString()方法究竟返回的是什么

最近项目上线后遇到exception没有堆栈信息。所以跟踪一下 源码,其中主要的code如下:

        // Returns the stack trace as a string.  If no stack trace is
        // available, null is returned.
        public virtual String StackTrace
        {
#if FEATURE_CORECLR
            [System.Security.SecuritySafeCritical] 
#endif
            get 
            {
                // By default attempt to include file and line number info
                return GetStackTrace(true);
            }
        }

        // Computes and returns the stack trace as a string
        // Attempts to get source file and line number information if needFileInfo
        // is true.  Note that this requires FileIOPermission(PathDiscovery), and so
        // will usually fail in CoreCLR.  To avoid the demand and resulting
        // SecurityException we can explicitly not even try to get fileinfo.
        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        private string GetStackTrace(bool needFileInfo)
        {
            string stackTraceString = _stackTraceString;
            string remoteStackTraceString = _remoteStackTraceString;

#if !FEATURE_CORECLR
            if (!needFileInfo)
            {
                // Filter out file names/paths and line numbers from _stackTraceString and _remoteStackTraceString.
                // This is used only when generating stack trace for Watson where the strings must be PII-free.
                stackTraceString = StripFileInfo(stackTraceString, false);
                remoteStackTraceString = StripFileInfo(remoteStackTraceString, true);
            }
#endif // !FEATURE_CORECLR

            // if no stack trace, try to get one
            if (stackTraceString != null)
            {
                return remoteStackTraceString + stackTraceString;
            }
            if (_stackTrace == null)
            {
                return remoteStackTraceString;
            }

            // Obtain the stack trace string. Note that since Environment.GetStackTrace
            // will add the path to the source file if the PDB is present and a demand
            // for FileIOPermission(PathDiscovery) succeeds, we need to make sure we 
            // don't store the stack trace string in the _stackTraceString member variable.
            String tempStackTraceString = Environment.GetStackTrace(this, needFileInfo);
            return remoteStackTraceString + tempStackTraceString;
         }
    
#if FEATURE_CORECLR
        [System.Security.SecuritySafeCritical] 
#endif
        public override String ToString()
        {
            return ToString(true, true);
        }

        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        private String ToString(bool needFileLineInfo, bool needMessage) {
            String message = (needMessage ? Message : null);
            String s;

            if (message == null || message.Length <= 0) {
                s = GetClassName();
            }
            else {
                s = GetClassName() + ": " + message;
            }

            if (_innerException!=null) {
                s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + 
                "   " + Environment.GetResourceString("Exception_EndOfInnerExceptionStack");

            }

            string stackTrace = GetStackTrace(needFileLineInfo);
            if (stackTrace != null)
            {
                s += Environment.NewLine + stackTrace;
            }

            return s;
        }
    
        

Exception的StackTrace属性只返回当前对象的站信息,toString方法首先需要获取当前的Message,然后获取内部exception的tostring方法,最后获取 GetStackTrace方法的返回值,该方法主要内容来源于 Environment.GetStackTrace方法,其实现code如下:

        internal static String GetStackTrace(Exception e, bool needFileInfo)
        {
            // Note: Setting needFileInfo to true will start up COM and set our
            // apartment state.  Try to not call this when passing "true" 
            // before the EE's ExecuteMainMethod has had a chance to set up the
            // apartment state.  -- 
            StackTrace st;
            if (e == null)
                st = new StackTrace(needFileInfo);
            else
                st = new StackTrace(e, needFileInfo);

            // Do no include a trailing newline for backwards compatibility
            return st.ToString( System.Diagnostics.StackTrace.TraceFormat.Normal );
        }

调用的是StackTrace的tostring方法,其实现如下:

  internal String ToString(TraceFormat traceFormat)
        {
            bool displayFilenames = true;   // we'll try, but demand may fail
            String word_At = "at";
            String inFileLineNum = "in {0}:line {1}";

            if(traceFormat != TraceFormat.NoResourceLookup)
            {
                word_At = Environment.GetResourceString("Word_At");
                inFileLineNum = Environment.GetResourceString("StackTrace_InFileLineNumber");
            }
            
            bool fFirstFrame = true;
            StringBuilder sb = new StringBuilder(255);
            for (int iFrameIndex = 0; iFrameIndex < m_iNumOfFrames; iFrameIndex++)
            {
                StackFrame sf = GetFrame(iFrameIndex);
                MethodBase mb = sf.GetMethod();
                if (mb != null)
                {
                    // We want a newline at the end of every line except for the last
                    if (fFirstFrame)
                        fFirstFrame = false;
                    else
                        sb.Append(Environment.NewLine);
                    
                    sb.AppendFormat(CultureInfo.InvariantCulture, "   {0} ", word_At);

                    Type t = mb.DeclaringType;
                     // if there is a type (non global method) print it
                    if (t != null)
                    {                                   
                        sb.Append(t.FullName.Replace('+', '.'));
                        sb.Append(".");
                    }
                    sb.Append(mb.Name);

                    // deal with the generic portion of the method
                    if (mb is MethodInfo && ((MethodInfo)mb).IsGenericMethod)
                    {
                        Type[] typars = ((MethodInfo)mb).GetGenericArguments();
                        sb.Append("[");
                        int k=0;
                        bool fFirstTyParam = true;
                        while (k < typars.Length)
                        {
                            if (fFirstTyParam == false)
                                sb.Append(",");
                            else
                                fFirstTyParam = false;

                            sb.Append(typars[k].Name);             
                            k++;
                        }   
                        sb.Append("]");    
                    }

                    // arguments printing
                    sb.Append("(");
                    ParameterInfo[] pi = mb.GetParameters();
                    bool fFirstParam = true;
                    for (int j = 0; j < pi.Length; j++)
                    {
                        if (fFirstParam == false)
                            sb.Append(", ");
                        else
                            fFirstParam = false;

                        String typeName = "<UnknownType>";
                        if (pi[j].ParameterType != null)
                            typeName = pi[j].ParameterType.Name;
                        sb.Append(typeName + " " + pi[j].Name);             
                    }   
                    sb.Append(")");

                    // source location printing
                    if (displayFilenames && (sf.GetILOffset() != -1))
                    {
                        // If we don't have a PDB or PDB-reading is disabled for the module,
                        // then the file name will be null.
                        String fileName = null;
                        
                        // Getting the filename from a StackFrame is a privileged operation - we won't want
                        // to disclose full path names to arbitrarily untrusted code.  Rather than just omit
                        // this we could probably trim to just the filename so it's still mostly usefull.
                        try
                        {
                            fileName = sf.GetFileName();
                        }
#if FEATURE_CAS_POLICY
                        catch (NotSupportedException)
                        {
                            // Having a deprecated stack modifier on the callstack (such as Deny) will cause
                            // a NotSupportedException to be thrown.  Since we don't know if the app can
                            // access the file names, we'll conservatively hide them.
                            displayFilenames = false;
                        }
#endif // FEATURE_CAS_POLICY
                        catch (SecurityException)
                        {
                            // If the demand for displaying filenames fails, then it won't
                            // succeed later in the loop.  Avoid repeated exceptions by not trying again.
                            displayFilenames = false;
                        }

                        if (fileName != null) 
                        {
                            // tack on " in c:\tmp\MyFile.cs:line 5"
                            sb.Append(' ');
                            sb.AppendFormat(CultureInfo.InvariantCulture, inFileLineNum, fileName, sf.GetFileLineNumber());
                        }
                    }

#if FEATURE_EXCEPTIONDISPATCHINFO
                    if (sf.GetIsLastFrameFromForeignExceptionStackTrace())
                    {
                        sb.Append(Environment.NewLine);
                        sb.Append(Environment.GetResourceString("Exception_EndStackTraceFromPreviousThrow"));
                    }
#endif // FEATURE_EXCEPTIONDISPATCHINFO
                }
            }

            if(traceFormat == TraceFormat.TrailingNewLine)
                sb.Append(Environment.NewLine);
            
            return sb.ToString(); 
        }

这个方法最主要的还是   StackFrame sf = GetFrame(iFrameIndex);   它返回跟踪栈的信息。跟踪栈的信息主要来源于StackTrace的构造函数

  public StackTrace(Exception e, bool fNeedFileInfo)
        {
            if (e == null)
                throw new ArgumentNullException("e");
            Contract.EndContractBlock();

            m_iNumOfFrames = 0;
            m_iMethodsToSkip = 0;
            CaptureStackTrace(METHODS_TO_SKIP, fNeedFileInfo, null, e);
        }

核心实现CaptureStackTrace code如下:

  private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread,
                                       Exception e)
        {
            m_iMethodsToSkip += iSkip;
    
            StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread);
    
            GetStackFramesInternal(StackF, 0, e);
    
            m_iNumOfFrames = StackF.GetNumberOfFrames();

            if (m_iMethodsToSkip > m_iNumOfFrames)
                m_iMethodsToSkip = m_iNumOfFrames;

            if (m_iNumOfFrames != 0)
            {
                frames = new StackFrame[m_iNumOfFrames];

                for (int i = 0; i < m_iNumOfFrames; i++)
                {
                    bool fDummy1 = true;
                    bool fDummy2 = true;
                    StackFrame sfTemp = new StackFrame(fDummy1, fDummy2);

                    sfTemp.SetMethodBase(StackF.GetMethodBase(i));
                    sfTemp.SetOffset(StackF.GetOffset(i));
                    sfTemp.SetILOffset(StackF.GetILOffset(i));

#if FEATURE_EXCEPTIONDISPATCHINFO
                    sfTemp.SetIsLastFrameFromForeignExceptionStackTrace(StackF.IsLastFrameFromForeignExceptionStackTrace(i));
#endif // FEATURE_EXCEPTIONDISPATCHINFO

                    if (fNeedFileInfo)
                    {
                        sfTemp.SetFileName(StackF.GetFilename (i));
                        sfTemp.SetLineNumber(StackF.GetLineNumber(i));
                        sfTemp.SetColumnNumber(StackF.GetColumnNumber(i));
                    } 

                    frames[i] = sfTemp;
                }

                // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace,
                // but this is not desired if building a stack trace from an exception.
                if (e == null)
                    m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames);

                m_iNumOfFrames -= m_iMethodsToSkip;
                if (m_iNumOfFrames < 0)
                   {
                       m_iNumOfFrames = 0;
                   }
            }

            // In case this is the same object being re-used, set frames to null
            else
                frames = null;
        }
    

顺便提一下,VS在release模式下是可以调试的,也可以获取堆栈信息。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java 实现连接sql server 20002007-12-16 13:28:00.0 第一种:通过ODBC连接数据库 JAVA语言的跨平台的工作能力(Write Once ,Run Anywhere)、优秀的图像处理能力(我相信现在没有那种语言可以超过JAVA在网络上的图形处理能力)、网络通信功能、通过JDBC数据库访问技术等等,让我们谁都不可否认JAVA语言是SUN公司对于计算机界的一个巨大的贡献。笔者可以描述这样一个场景:有一天你上网完全可以不用IE 或者NETSCAPE,上网就像是玩游戏,你可以获得游戏那么精美的图像和互动的感觉,如果你玩过UO,也许你就知道那种感觉了,但是JAVA做成的东西一定会超过UO的,因为不单单是游戏,也不是单单是浏览器,如果你愿意(要你有钱,有时间,有优秀的JAVA人才)你可以把所有的这一切用Java完全集成出来!!!我不是夸大JAVA的功能,大家可以访问一下http://www.simchina.net的那个社区程序,你就能找到一种感觉了:相信我没有说什么假话 。好了,不说废话了,现在我向你介绍JAVA的数据库访问技术----JDBC数据库访问技术(你可千万不要搞成ODBC了哟!)。 JDBC技术事实上是一种能通过JAVA语言访问任何结构化数据库的应用程序接口(API)(Sun这样说的,我也不知道是不是真的),而且现在的JDBC 3.0据Sun说也能访问Execel等电子表格程序! JDBC对于数据库的访问有四种方式,我们这里只是介绍两种: 第一种是通过ODBC做为“桥”(Bridge)对数据库访问,第二种是直接对数据库访问。 我们先来看看第一种JDBC<-->ODBC访问的流程: JDBC Driver Mannager->JDBC<->ODBC桥->ODBC->数据库客户机驱动库->数据库服务器->返回查询结果,在这种访问中值的我们注意的是虽然JAVA是"Write Once ,Run Anywhere",但是如果通过这种访问的话,需要客户端必须设置ODBC和有相应的数据库客户机的驱动,当你看了下面的另外一个流程的时候或许你会想:明明下一种更方面,为什么还要有这个东西的产生!呵呵,因为,未必所有的数据库服务器提供商都提供下面的JDBC驱动程序(给JDBC访问提供相应的接口),所以就有了JDBC<->ODBC Bridge。 接着再让我们来看看第二种访问流程: JDBC Driver Mannager->局部JDBC驱动->客户端数据库->数据库服务器->返回查询结果,这种访问事实上是转换JDBC调用为相应的数据库(Oracle, Sybase, Informix, DB2, 和其他的数据库数据库管理系统)的客户端API调用(这么说,不知道大家能不能懂,说简单点就好像ASP不是通过DSN对数据库访问而是通过OLEDB访问,说道这里我还是不知道大家能不能明白我的意思。哎呀,不要扔鸡蛋嘛!),这种方式的访问需要相应的数据库提供商提供相应的JDBC驱动程序,但是有一种好处,可以独立于odbc用于可以随处可Run的客户端的浏览器中的Applet程序。 我们下面将给大家一个通过JDBC-ODBC桥数据库访问的实例,但是在看下面的事例前我想问大家一次:JDK1.3装了吗?数据库驱动装了吗(我使用的是SQLserver)?你该没有使用Linux吧?虽然java支持Linux,但是老兄我可没有使用Linux哟(这同JAVA的Write Once ,Run Anywhere没有关系),由于使用了运行于Win下面的ODBC,我建议你看看这篇东西http://www.aspcn.com/showarticle.asp?id=112,否则你要是有了问题,出不了结果那岂不是要怪我(不过欲加之罪,何患无吃... ...),冤枉呀! 哎呀,说了这么多的废话,还是让我们来看看到底JDBC的调用吧!既然我们是通过odbc访问数据库,所以这个odbc是跑不了的,我们先来设置你的odbc:打开你的odbc数据源->选择系统dsn(Click加新的dsn-)->接下来输入选择数据库类型、输入dsn名:、选择服务器、连接数据库的方式、输入数据库的登陆用户和密码->测试连接,如果测试成功的话,那么你的dsn就建立好了,我的dsn名为Sqlserver.使用的是sqlserver7.0,以 “sa”登陆,密码为空。这些东西都是后面要用道的! 好了下面让我们来看程序代码: (该代码已经通过运行) //########################################################### //代码开始 //########################################################### import java.sql.*; //加载java数据连接包,java基本所有的数据库的调用的都在这个东西里面 public class InsertCoffees { public static void main(String args[]) { String url = "jdbc:odbc:sqlserver"; //取得连接的url名,注意sqlserver是dsn名 Connection con; //实例化一个Connection对象 Statement stmt; String query = "select * from col_link"; //选择所有的Col_link表中的数据输出 try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加载jdbc-odbc桥驱动 } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: "); //加载jdbc-odbc桥错误 System.err.println(e.getMessage()); //其他错误 } try { con = DriverManager.getConnection(url, "sa", ""); //数据库连接 stmt = con.createStatement(); //Create 一个声明 stmt.executeUpdate("CREATE TABLE col_link (sitename varchar (20) NULL ,siteurl varchar (50) NULL) "); //执行了一个sql语句生成了一个表col_link的表 stmt.executeUpdate("insert into col_link values('ASP中华网','http://www.aspcn.com')"); stmt.executeUpdate("insert into col_link values('永远到底有多远','http://xuankong.com')"); //执行一个insert into语句 stmt.executeUpdate("update col_link set siteurl='http://www.aspcn.com/xuankong/xuankongt.jpg' where siteurl='http://xuankong.com'"); //执行一个update语句,更新数据库 ResultSet rs = stmt.executeQuery(query); //返回一个结果集 System.out.println("Col_link表中的数据如下(原始数据)"); //下面的语句使用了一个while循环打印出了col_link表中的所有的数据 System.out.println("站点名 "+" "+"站点地址"); System.out.println("---------------"+" "+"----------------"); while (rs.next()) { String s = rs.getString("sitename"); String f = rs.getString("siteurl"); //取得数据库中的数据 System.out.println(s + " " + f); /*String t = rs.getString(1); String l = rs.getString(2); System.out.println(t + " " + l);*/ /*jdbc提供了两种方法识别字段,一种是使用getXXX(注意这里的getXXX表示取不同类型字段的不同的方法)获得字段名, 第二种*是通过字段索引,在这里我把第二种方法注释了*/ /*你可以访问这个连接获得getxxx的用法:http://java.sun.com/docs/books/tutorial/jdbc/basics/_retrievingTable.html*/ } stmt.close(); con.close(); //上面的语句关闭声明和连接 } catch(SQLException ex) { System.err.println("SQLException: " + ex.getMessage()); //显示数据库连接错误或者查询错误 } } } //########################################################### //代码结束 //########################################################### 在上面这个程序中我想你展示了如何使用JDBC-ODBC连接数据库,使用SQL语句生成一个表,使用SELECT、INSERT 、UPDATE语句取的、插入和更新一个表中的数据,如何通过字段名和字段索引访问数据库中的东东!我希望你能从上面的代码真正的学习到一些东西! 发挥你的想象力,设想一下JAVA到底,比如说可以通过数据库做一个不需要GUI(图形用户界面)的聊天室,呵呵,感觉起来就像在DOS环境下打字的聊天室!哈哈! 最后需要说的是笔者的调试上面程序的环境:WIN2000 , JDK1.3,MS SQLSERVER编辑软件:EDITPLUS 2.01a(这最后的东西可不是废话,虽然早就了一些专业的JAVA开发工具,但是笔者建议JAVA初学者使用文本软件开发JAVA程序) 第二种:直接用jdbc访问数据库 (1) 该实例已经运行通过 jsp连接Sql Server7.0/2000数据库 testsqlserver.jsp如下: <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.sql.*"%> <html> <body> <%Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance(); String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs"; //pubs为你的数据库的 String user="sa"; String password=""; Connection conn= DriverManager.getConnection(url,user,password); Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); String sql="select * from test"; ResultSet rs=stmt.executeQuery(sql); while(rs.next()) {%> 您的第一个字段内容为:<%=rs.getString(1);%> 您的第二个字段内容为:<%=rs.getString(2);%> <%}%> <%out.print("数据库操作成功,恭喜你");%> <%rs.close(); stmt.close(); conn.close(); %> </body> </html> (2)java访问sqlserver服务器 第一步:安装jdbc 点击SQL Server for JDBC驱动程序安装程序setup.exe(可以到微软网站下载 http://msdn.microsoft.com/library/default.asp?rul=/downloads/list/sqlserver.asp下载) 第二步:设置系统变量classpath 假设SQL Server for JDBC 驱动程序安装在d:\jdbc\,则classpath应该设置如下: classpath:=.;…;d:\jdbc\lib; d:\jdbc\lib\mssqlserver.jar; d:\jdbc\lib\msutil.jar; d:\jdbc\lib\msbase.jar; 注意:设置时要在最前面的点号和分号 第三步:编辑java程序并且运行 实例1如下: //import com.microsoft.*; //注意:在java与sql server 连接时不需要这个包,其他书上说这个包是必需的,这个问题有待进一步讨论 import java.sql.*; import java.net.URL; class insert { public static void main(String[] args) { String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=northwind"; String query="select * from categories"; String query1="insert categories values(10,'Hanbao','Sweet')"; String query2="insert categories values(11,'Naicha','Coffee taste')"; try { Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver"); Connection con=DriverManager.getConnection(url,"sa","739555"); Statement stmt=con.createStatement(); stmt.executeUpdate(query1); stmt.executeUpdate(query2); stmt.close(); con.close(); } catch(SQLException ex) { } catch(java.lang.Exception ex) { ex.printStackTrace(); } } } 实例2如下: //import com.microsoft.*; //注意:在java与sql server 连接时不需要这个包,其他书上说这个包是必需的,这个问题有待进一步讨论 import java.sql.*; import java.net.URL; class java2sqlserver { public static void main(String[] args) { String url="jdbc:microsoft:sqlserver://localhost:1433;User=sa;Password=739555;DatabaseName=northwind"; String query="Select * From Categories"; try { Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver"); //DriverManager.setLogStream(System.out); Connection con=DriverManager.getConnection(url); checkForWarning(con.getWarnings()); Statement stmt=con.createStatement(); ResultSet rs=stmt.executeQuery(query); dispResultSet(rs); rs.close(); stmt.close(); con.close(); } catch(SQLException ex) { System.out.println(ex.toString()+"----SQLException caught----"); while(ex!=null) { System.out.print("SQLState:"+ex.getSQLState()); System.out.print("Message:"+ex.getMessage()); System.out.print("Vendor:"+ex.getErrorCode()); ex=ex.getNextException(); System.out.println(""); } } catch(java.lang.Exception ex) { ex.printStackTrace(); } } private static boolean checkForWarning(SQLWarning warn) { boolean rc=false; if(warn!=null) { System.out.println("----Warning----"); rc=true; while(warn!=null) { System.out.print("SQLState:"+warn.getSQLState()); System.out.print("Message:"+warn.getMessage()); System.out.print("Vendor:"+warn.getErrorCode()); System.out.println(""); warn=warn.getNextWarning(); } } return rc; } private static void dispResultSet(ResultSet rs) throws SQLException { int i; ResultSetMetaData rsmd=rs.getMetaData(); int numCols=rsmd.getColumnCount(); for(i=1;i<=numCols;i++) { if(i>1) System.out.print(", "); System.out.print(rsmd.getColumnLabel(i)); } System.out.println(""); boolean more=rs.next(); while(more) { for(i=1;i<numCols;i++) { if(i<1) System.out.print(", "); System.out.println(rs.getString(i)); } System.out.println(""); more=rs.next(); } } //System.out.println("Hello World!"); } 以上两个实例笔者已经通过运行!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值