在 Jython 中全面捕获异常

2023-12-03

到目前为止,这是我尝试捕获 Jython 代码中的所有异常。我发现,最困难的事情是当您重写 Java 类中的方法时捕获异常:使用下面的“vigil”装饰器(它还测试 EDT/Event Despatch Thread 状态是否正确)您可以找到第一行代码抛出的位置...这样您就可以识别方法本身。但不是线。

此外,通过 Python 和 Java 堆栈追踪堆栈帧完全超出了我的能力范围。显然,似乎存在这些层又层的“代理”类,这无疑是 Jython 机制不可避免的一部分。如果有比我聪明得多的人对这个问题感兴趣那就太好了!

注意,这是如何使用“vigil”装饰器的示例:

    class ColumnCellRenderer( javax.swing.table.DefaultTableCellRenderer ):
        @vigil( True ) # means a check is done that the thread is the EDT, as well as intercepting Python Exceptions and Java Throwables...
        def getTableCellRendererComponent( self, table, value, isSelected, hasFocus, row, column):
            super_comp = self.super__getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column)
            super_comp.foreground = java.awt.Color.black
            super_comp.font = main_frame_self.m_plain_font
            ...

...这是我用来捕获东西的三个函数...

def custom_hook(type_of_e, e, tb ):
    """
Method to catch Python-style BaseExceptions, using the command sys.excepthook = custom_hook.
The first thing this method needs to do in Jython is to determine whether this is a Java 
java.lang.Throwable or not.  If it is this JThrowable
must be handled by the code which caters for B{uncaught Java Throwables}.        
    """
    try:

        if 'tb' not in locals():
            tb = None
        logger.error("Python custom_hook called...\ntype of e: %s\ne: %s\ntb: %s" % ( unicode( type_of_e ), unicode( e ), 
                                                                                    unicode( tb ) ))
        msg = ''.join( traceback.format_exception(type_of_e, e, tb ))
        logger.error( "traceback:\n" + msg )
    except BaseException, e:
        logger.error( "exception in Python custom_hook!:\n%s" % e )
        raise e
sys.excepthook = custom_hook

class JavaUncaughtExceptHandler( java.lang.Thread.UncaughtExceptionHandler ):
    """
java.lang.Class to catch any Java Throwables thrown by the app.        
    """
    def uncaughtException( self, thread, throwable ):
        try:
            '''
NB getting the Java stack trace like this seems to produce a very different trace 
from throwable.printStackTrace()... why?             
            '''
            # we want a single log message
            exception_msg = "\n*** uncaught Java Exception being logged in %s:\n" % __file__
            baos = java.io.ByteArrayOutputStream()
            ps = java.io.PrintStream(baos)
            throwable.printStackTrace( ps )
            # remove multiple lines from Java stack trace message
            java_stack_trace_lines = unicode( baos.toString( "ISO-8859-1" )).splitlines()
            java_stack_trace_lines = filter( None, java_stack_trace_lines  )
            normalised_java_stack_trace = '\n'.join( java_stack_trace_lines )
            exception_msg += normalised_java_stack_trace + '\n'
            python_traceback_string = traceback.format_exc()
            exception_msg += "Python traceback:\n%s" % python_traceback_string
            logger.error( exception_msg )
        except (BaseException, java.lang.Throwable ), e:
            logger.error( "*** exception in Java exception handler:\ntype %s\n%s" % ( type( e ), unicode( e ) ) )
            raise e
        # NB printStackTrace causes the custom_hook to be invoked... (but doesn't print anything)
java.lang.Thread.setDefaultUncaughtExceptionHandler( JavaUncaughtExceptHandler()  )


def vigil( *args ):
    """
Decorator with two functions.  
1. to check that a method is being run in the EDT or a non-EDT thread; 
2. to catch any Java Throwables which otherwise would not be properly caught and documented: in particular, 
with normal Java error-trapping in Jython it seems impossible to determine the line number at which an 
Exception was thrown.  This at least records the line at which a Java java.lang.Throwable
was thrown.
    """
    if len( args ) != 1:
        raise Exception( "vigil: wrong number of args (should be 1, value: None/True/False): %s" % str( args ))
    req_edt = args[ 0 ]
    if req_edt and type( req_edt ) is not bool:
        raise Exception( "vigil: edt_status is wrong type: %s, type %s" % ( req_edt, type( req_edt )) )
    def real_decorator( function ):
        if not hasattr( function, '__call__' ):
            raise Exception( "vigil: function %s does not have __call__ attr, type %s" 
                % ( function, type( function )) )

        # NB info about decorator location can't be got when wrapper called, so record it at this point
        penultimate_frame = traceback.extract_stack()[ -2 ] 
        decorator_file = penultimate_frame[ 0 ]    
        decorator_line_no = penultimate_frame[ 1 ]    
        def wrapper( *args, **kvargs ):
            try:
                # TODO is it possible to get the Python and/or Java stack trace at this point?
                if req_edt and javax.swing.SwingUtilities.isEventDispatchThread() != req_edt:
                    logger.error( "*** vigil: wrong EDT value, should be %s\nfile %s, line no %s, function: %s\n" % 
        ( "EDT" if req_edt else "non-EDT", decorator_file, decorator_line_no, function ))
                return function( *args, **kvargs )
            except ( BaseException, java.lang.Throwable ), e:
                ''' NB All sorts of problems if a vigil-protected function throws an exception:
1) just raising e means you get a very short stack trace...
2) if you list the stack trace elements here you get a line (seemingly inside the function where the 
exception occurred) but often the wrong line!
3) Python/Java stack frames: how the hell does it all work???
4) want a single error message to be logged                
                ''' 
                msg = "*** exception %s caught by vigil in file %s\nin function starting line %d" % ( e, decorator_file, decorator_line_no )
                logger.error( msg )
                frame = inspect.currentframe()
                # the following doesn't seem to work... why not?
                python_stack_trace = traceback.format_stack(frame)
                python_stack_string = "Python stack trace:\n"
                for el in python_stack_trace[ : -1 ]:
                    python_stack_string += el
                logger.error( python_stack_string )
                if isinstance( e, java.lang.Throwable ):
                    # NB problems with this stack trace: although it appears to show the 
                    # correct Java calling pathway, it seems that the line number of every file and method 
                    # is always shown as being the last line, wherever the exception was actually raised.
                    # Possibly try and get hold of the actual Pyxxx objects ... (?)
                    java_stack_trace = e.stackTrace
                    java_stack_string = "Java stack trace:\n"
                    for el in java_stack_trace:
                        java_stack_string += "  %s\n" % unicode( el )
                    logger.error( java_stack_string )
                    raise e
        return wrapper
    return real_decorator

PS 当然可以用 try ... except... 对每个被重写的 Java 方法进行顶部和尾部操作,但这有什么乐趣呢?说真的,即使这样做我也无法找到抛出异常的行......


下面是 Jython 的套接字模块中使用的装饰器示例,用于将 Java 异常映射到 Python 异常。我没有读你的vigil装饰器太紧密了,因为它做了很多工作,但我把它放在这里以防它可能有帮助:

def raises_java_exception(method_or_function):
    """Maps java socket exceptions to the equivalent python exception.
    Also sets _last_error on socket objects so as to support SO_ERROR.
    """

    @wraps(method_or_function)
    def handle_exception(*args, **kwargs):
        is_socket = len(args) > 0 and isinstance(args[0], _realsocket)
        try:
            try:
                return method_or_function(*args, **kwargs)
            except java.lang.Exception, jlx:
                raise _map_exception(jlx)
        except error, e:
            if is_socket:
                args[0]._last_error = e[0]
            raise
        else:
            if is_socket:
                args[0]._last_error = 0
    return handle_exception

我们在这里看到的主要是我们正在调度它是否是一个 Java 异常(java.lang.Exception) 或不。我想这可以推广到java.lang.Throwable,尽管尚不清楚在这种情况下可以做什么java.lang.Error在任何情况下。当然没有任何对应于套接字错误!

上面的装饰器依次使用了_map_exception函数来解开 Java 异常。正如您所看到的,这里的应用程序非常特定:

def _map_exception(java_exception):
    if isinstance(java_exception, NettyChannelException):
        java_exception = java_exception.cause  # unwrap
    if isinstance(java_exception, SSLException) or isinstance(java_exception, CertificateException):
        cause = java_exception.cause
        if cause:
            msg = "%s (%s)" % (java_exception.message, cause)
        else:
            msg = java_exception.message
        py_exception = SSLError(SSL_ERROR_SSL, msg)
    else:
        mapped_exception = _exception_map.get(java_exception.__class__)
        if mapped_exception:
            py_exception = mapped_exception(java_exception)
        else:
            py_exception = error(-1, 'Unmapped exception: %s' % java_exception)
    py_exception.java_exception = java_exception
    return _add_exception_attrs(py_exception)

代码中存在一些笨拙的地方,我确信还有改进的空间,但总的来说,它确实使任何经过修饰的代码更容易遵循。例子:

@raises_java_exception
def gethostname():
    return str(InetAddress.getLocalHost().getHostName())
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Jython 中全面捕获异常 的相关文章

随机推荐

  • @EJB 注释与 JNDI 查找

    是否存在使用 JNDI 比使用注入无状态会话 bean 更好的情况 EJB注解 我们将 JSF 1 2 与 Sun Application Server 9 0 01 结合使用 我们的团队正在讨论在托管 Bean 中使用 SLSB 时哪种方
  • 如何防止长按 EditText Widget 时显示虚拟键盘?

    我的应用程序中有一个 EditText 小部件 我已将其设置为只读 我想知道用户何时长按它 如果用户点击此小部件 我不希望弹出虚拟键盘 为了阻止虚拟键盘出现 我使用这个 EditText 文本 EditText findViewById R
  • 插入数据并获取返回的 id 后如何修复 DapperExtensions 错误

    I use 简洁的扩展将数据拉取和推送到数据库 I use unsigned intid 作为我的主键database并在class以及 我的课看起来像这样 public class Product Column id public uin
  • CodePipeline 的 Cloudformation 模板

    我们有一个 aws 设置 其中有一个测试帐户和一个生产帐户 我们的代码提交 java lambda 位于我们的测试帐户中 我们希望使用 CodePipeline 将代码从此处部署到我们的测试帐户和生产帐户 我想知道是否有人知道任何可以执行此
  • 另一个视图控制器中属性的内联 KVO

    我有一个带有动态变量 值 的 vc 我需要知道它何时在调用 cv 的闭包中发生更改 目标VC objc dynamic var value String source if let vc TagButtonPopupViewControll
  • 如何确认邮件来源

    我从我的 smtp 服务器发送电子邮件 例如 设置From to 电子邮件受保护 收件人会认为电子邮件来自anydomain 如何确认邮件来源 处理电子邮件伪造的方法有多种 Use PGP or SSL 签名证书 Use SPF 检查Rec
  • 使用 css 在子菜单前添加三角形

    如何在下面的示例中添加三角形Fiddle 我需要删除具有白色背景的父菜单并显示三角形以使其看起来更像这样 我尝试添加以下 css 但它不起作用 dropdown li first child gt a after content posit
  • 以编程方式将文件夹复制并粘贴到映射的网络驱动器中

    我试图在映射的网络驱动器上复制一个文件夹 不是文件 而是整个目录 并将其新版本以不同的名称粘贴到同一位置 如果我使用本地驱动器 下面的代码效果很好 但是 我在使用网络驱动器时遇到身份验证错误 DirectoryCopy mappedserv
  • 在 Java-8 中重构多个 If' 语句

    我需要验证班级中的必填字段 例如 9字段不得是null 我需要检查它们是否全部为空 但我现在使用多个 if 语句 如下所示 StringBuilder mandatoryExcessFields new StringBuilder MAND
  • 没有 ObservableDataService 的提供者

    我收到错误 No provider for ObservableDataService ObservableDataService https github com sanex3339 bannerscreator blob master
  • 使用 mutate_at 用列名更新单元格值

    我正在处理调查数据 有些问题要求参与者检查所有适用于他们的选项 在我当前拥有的数据框中 每个可能的响应都有一列 如果参与者选择了该选项 则记录值为 1 例如 对于问题 您在工作中经历过以下哪种情绪 使用选项 无聊 压力 满足 我的数据框将如
  • 将表单输入值发送到 URL

    我有一个简单的搜索表单
  • GitHub 中的分支之间合并

    我分叉了一个 GitHub 存储库 然后我向我的叉子推送了一些更改 然后原始存储库合并了我的更改和其他一些更改 现在 我想合并那些我缺少的更改 我尝试了简单的拉动 然后推送 但这会产生重复的提交 最好的方法是什么 您可能对每个存储库都有一个
  • ModuleNotFoundError:没有名为“camelot”的模块

    我想从 pdf 中提取表格并为此 我用的是卡米洛特 但每当我尝试导入它时 我都会收到此错误 import camelot Traceback most recent call last File
  • C/C++签名中两个const的含义

    我一直在包装一个 gl 文件scheme并且失败了两次gl h标头 我使用的是 OSx 所以它可能依赖于平台 但我在生活中的其他地方从未见过这种语法 typedef void glMultiDrawElementsProcPtr GLenu
  • 使用结构体在 C 中输入 CSV 文件

    我想打印来自的数据 csv逐行文件 由comma分隔符 此代码打印垃圾值 enum gender M F struct student int stud no enum gender stud gen char stud name 100
  • 使用 EF4 实施识别关系

    我目前的情况是需要删除实体而无法访问关联的实体ObjectContext 我读到了有关识别关系的内容 它们似乎正是我所需要的 一旦一个对象不再被其 父 对象引用 我想删除该对象 我正在使用 Visual Studio 2010 Premiu
  • 如何在Python中比较列表/集合的列表?

    比较两个列表 集合并输出差异的最简单方法是什么 是否有任何内置函数可以帮助我比较嵌套列表 集合 Inputs First list Test doc 1a1a1a 1111 Test2 doc 2b2b2b 2222 Test3 doc 3
  • 是否可以使用元组中传递的参数的所有可能的 K 组合(带重复)来调用方法?

    所需的行为可以如下所示 void foo int x int y std cout lt lt x lt lt lt lt y lt lt std endl int main all combinations lt 2 gt foo std
  • 在 Jython 中全面捕获异常

    到目前为止 这是我尝试捕获 Jython 代码中的所有异常 我发现 最困难的事情是当您重写 Java 类中的方法时捕获异常 使用下面的 vigil 装饰器 它还测试 EDT Event Despatch Thread 状态是否正确 您可以找