Q: I have called an external method in my application and want to catch exceptions that it may throw. Can I capture java. Lang. exception?
A: using a given method to handle all runtime and detection exceptions is inadequate to prevent external errors.
You can read the current javaworld article-"Java tip 134: when catching exception, don't cast your net too wide ". This article warned that it is not good to capture java. Lang. Exception and Java. Lang. throable. Capturing exceptions that you can specify is very important for code maintainability. However, this rule depends on a special environment. If you do not want your program to crash and keep the security exceptions of your data structure, you must capture the real exceptions thrown.
For example, assume that you have a server application that loads this interface:
Public interface IFoo { /** * This method can't throw any checked exceptions... or can it? */ Void bar (); } // End of interface |
The reason for giving parameters is that we will notify you where such a service is located, and different ifoo implementations can be loaded from external resources. Write the following code:
Try { IFoo foo =... // get an IFoo implementation Foo. bar (); } Catch (RuntimeException ioe) { // Handle 'ioe '... } Catch (Error e) { // Handle or re-throw 'E '... } |
And you have handled all possible exceptions here. You don't need to add any exceptions to capture java. Io. ioexception here, because the ifoo implementation didn't throw it from ifoo. Bar (), right? (In fact, if you add a catch java. Io. ioexception block, the compiler may discard it as an inaccessible exception)
Error. In the evilfoo class I wrote, the bar () method proves any exceptions that will throw you to the class constructor:
Public void bar () { EvilThrow. throwThrowable (m_throwthis ); } |
Run the main method:
Public class Main { Public static void main (final String [] args) { // This try/catch block appears to intercept all exceptions that // IFoo. bar () can throw; however, this is not true Try { IFoo foo = new EvilFoo (new java. io. IOException ("SURPRISE! ")); Foo. bar (); } Catch (RuntimeException ioe) { // Ignore ioe } Catch (Error e) { // Ignore } } } // End of class |
You will see the java. Io. ioexception instance thrown from the bar () method without any capture block:
> JAVA-CP classes main Exception in thread "Main" Java. Io. ioexception: Surprise! At Main. Main (main. Java: 23) |
What happened here?
The main observation is that Java rules for detecting exceptions are only executed during compilation. During running, a JVM cannot ensure that the exception thrown by a method matches the thrown exception declared in this method. Because the responsibility of calling a method is to capture and handle all exceptions thrown from the call method. Any exceptions that are not declared by the call method will be ignored and the call stack will be rejected.
If the normal behavior is executed by the compiler, how can I create EvilFoo? There are at least two methods to create a Java method that throws exceptions without declaration:
Thread. stop (Throwable) is not supported in some cases, but it is still used and a Throwable is passed to the called Thread.
Compile separately: when compiling EvilFoo, you can not compile the IFoo temporary version that truly declares the bar () method to throw an exception detection.
I use the following option: the EvilThrow class that I compile and start to define:
Public abstract class evilthrow { Public static void throwthrowable (throwable) Throws throwable { Throw throwable; } } |
Next, I use the JasminVisitor decomposition result of Byte Code Engineering Library (BCEL), delete the declaration of the throwThrowable () method Throwable in the assembly Code, and compile the new version with Jasmin aggreger.
If you write a constructor to capture exceptions, it should always capture java. lang. Throwable, not just java. lang. Exception. This rule is suitable for developing and managing runtime applications and external components that must be executed that may contain errors or even malicious code. Make sure to capture Throwable and filter out error messages.
The following example shows what will happen if you do not follow this suggestion.
Example: Breaking SwingUtilities. invokeAndWait ()
Javax. swing. SwingUtilities. invokeAndWait () is a useful method for executing a thread on AWT. This method is called when an application thread must update graphical user interfaces and obey all Swing thread rules. An exception thrown without capturing Runnable. run () will be caught and encapsulated in an InvocationTragetException and thrown again.
Sun's J2SE1.4.1 assumes that such an uncaptured Exception is only a subclass of java. lang. Exception. Here is an analysis of an SwingUtilities. invokeAndWait () call java. awt. event. InvocationEvent:
Public void dispatch (){ If (catchexceptions ){ Try { Runnable. Run (); } Catch (exception e ){ Exception = E; } } Else { Runnable. Run (); }If (notifier! = Null ){ Synchronized (notifier ){ Notifier. policyall (); } } } |
The problem with this Code is that if runnable. run () throws a Throwable, the capture block does not exist and notifier. policyall () is never executed. Then the calling application thread will wait for a non-public lock Object (lock. wait () in java. awt. EventQueue. invokeAndWait () to be executed before ):
Public static void invokeandwait (runnable) Throws interruptedexception, invocationtargetexception {Class AWTInvocationLock {} Object lock = new AWTInvocationLock (); InvocationEvent event = new InvocationEvent (Toolkit. getdefatooltoolkit (), runnable, lock, True ); Synchronized (lock ){ Toolkit. getEventQueue (). postEvent (event ); Lock. wait (); } Exception eventException = event. getException (); If (eventException! = Null ){ Throw new InvocationTargetException (eventException ); } } |
Let EvilFoo implement the Runnable interface:
Public void run () { Bar (); } |
Then, call it in Main:
| SwingUtilities. invokeAndWait (new EvilFoo (new Throwable ("SURPRISE! "))); |
As you can see, untrusted code protects your code from exceptions in the execution path you are not ready to handle.