Java requires that each method address every checked exception that can be thrown during its execution either by handling the exception within a try-catch block or by declaring that the exception can propagate out of the method (via the throws clause). Unfortunately, there are a few techniques that permit undeclared checked exceptions to be thrown at runtime. Such techniques defeat the ability of caller methods to use the throws clause to determine the complete set of checked exceptions that could propagate from an invoked method. Consequently, such techniques must not be used to throw undeclared checked exceptions.

Noncompliant Code Example (Class.newInstance())

This noncompliant code example throws undeclared checked exceptions. The undeclaredThrow() method takes a Throwable argument and invokes a function that will throw the argument without declaring it. Although undeclaredThrow() catches any exceptions the function declares that it might throw, it nevertheless throws the argument it is given without regard to whether the argument is one of the declared exceptions. This noncompliant code example also violates ERR07-J. Do not throw RuntimeException, Exception, or Throwable. However, because of exception ERR08-J-EX0, it does not violate ERR08-J. Do not catch NullPointerException or any of its ancestors.
Any checked exception thrown by the default constructor of java.lang.Class.newInstance() is propagated to the caller even though Class.newInstance() declares that it throws only InstantiationException and IllegalAccessException. This noncompliant code example demonstrates one way to use Class.newInstance() to throw arbitrary checked and unchecked exceptions:

public class NewInstance {
  private static Throwable throwable;

  private NewInstance() throws Throwable {
    throw throwable;
  }

  public static synchronized void undeclaredThrow(Throwable throwable) {
    // These exceptions should not be passed
    if (throwable instanceof IllegalAccessException ||
        throwable instanceof InstantiationException) {
      // Unchecked, no declaration required
      throw new IllegalArgumentException(); 
    }

    NewInstance.throwable = throwable;
    try {
      // Next line throws the Throwable argument passed in above,
      // even though the throws clause of class.newInstance fails
      // to declare that this may happen
      NewInstance.class.newInstance();
    } catch (InstantiationException e) { /* Unreachable */
    } catch (IllegalAccessException e) { /* Unreachable */
    } finally { // Avoid memory leak
      NewInstance.throwable = null;
    }
  }
}

public class UndeclaredException {
  public static void main(String[] args) {   
    // No declared checked exceptions
    NewInstance.undeclaredThrow(
        new Exception("Any checked exception"));
  }
}

Noncompliant Code Example (Class.newInstance() Workarounds)

When the programmer wishes to catch and handle the possible undeclared checked exceptions, the compiler refuses to believe that any can be thrown in the particular context. This noncompliant code example attempts to catch undeclared checked exceptions thrown by Class.newInstance(). It catches Exception and dynamically checks whether the caught exception is an instance of the possible checked exception (carefully rethrowing all other exceptions).

public static void main(String[] args) {
  try {
    NewInstance.undeclaredThrow(
        new IOException("Any checked exception"));
  } catch (Throwable e) {
    if (e instanceof IOException) {
      System.out.println("IOException occurred");
    } else if (e instanceof RuntimeException) {
      throw (RuntimeException) e;
    } else {
      // Forward to handler
    }
  }
}

Compliant Solution (Constructor.newInstance())

This compliant solution uses java.lang.reflect.Constructor.newInstance() rather than Class.newInstance(). The Constructor.newInstance() method wraps any exceptions thrown from within the constructor into a checked exception called InvocationTargetException.

public static synchronized void undeclaredThrow(Throwable throwable) {
  // These exceptions should not be passed
  if (throwable instanceof IllegalAccessException ||
      throwable instanceof InstantiationException) {
    // Unchecked, no declaration required
    throw new IllegalArgumentException(); 
  }

  NewInstance.throwable = throwable;
  try {
    Constructor constructor =
        NewInstance.class.getConstructor(new Class<?>[0]);
    constructor.newInstance();
  } catch (InstantiationException e) { /* Unreachable */
  } catch (IllegalAccessException e) { /* Unreachable */
  } catch (InvocationTargetException e) {
    System.out.println("Exception thrown: "
        + e.getCause().toString());
  } finally { // Avoid memory leak
    NewInstance.throwable = null;
  }
}

Noncompliant Code Example (sun.misc.Unsafe)

This noncompliant code example is insecure both because it can throw undeclared checked exceptions and because it uses the sun.misc.Unsafe class. All sun.* classes are unsupported and undocumented because their use can cause portability and backward compatibility issues.

Classes loaded by the bootstrap class loader have the permissions needed to call the static factory method Unsafe.getUnsafe(). Arranging to have an arbitrary class loaded by the bootstrap class loader without modifying the sun.boot.class.path system property can be difficult. However, an alternative way to gain access is to change the accessibility of the field that holds an instance of Unsafe through the use of reflection. This approach works only when permitted by the current security manager (which would violate ENV03-J. Do not grant dangerous combinations of permissions). Given access to Unsafe, a program can throw an undeclared checked exception by calling the Unsafe.throwException() method.

import java.io.IOException;
import java.lang.reflect.Field;
import sun.misc.Unsafe;

public class UnsafeCode {
  public static void main(String[] args)
      throws SecurityException, NoSuchFieldException,
             IllegalArgumentException, IllegalAccessException {
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe u = (Unsafe) f.get(null);
    u.throwException(new IOException("No need to declare this checked exception"));
  }
}

Noncompliant Code Example (Generic Exception)

An unchecked cast of a generic type with parameterized exception declaration can also result in unexpected checked exceptions. All such casts are diagnosed by the compiler unless the warnings are suppressed.

interface Thr<EXC extends Exception> {
  void fn() throws EXC;
}

public class UndeclaredGen {
  static void undeclaredThrow() throws RuntimeException {
    @SuppressWarnings("unchecked")  // Suppresses warnings
    Thr<RuntimeException> thr = (Thr<RuntimeException>)(Thr)
      new Thr<IOException>() {
        public void fn() throws IOException {
          throw new IOException();
	}
      };
    thr.fn();
  }

  public static void main(String[] args) {
    undeclaredThrow();
  }
}

Noncompliant Code Example (Thread.stop(Throwable))

According to the Java API [API 2014], class Thread:

[Thread.stop()] This method was originally designed to force a thread to stop and throw a given Throwable as an exception. It was inherently unsafe (see Thread.stop() for details), and furthermore could be used to generate exceptions that the target thread was not prepared to handle.

For example, the following method is behaviorally identical to Java's throw operation but circumvents the compiler's attempts to guarantee that the calling method has declared all of the checked exceptions that it may throw.

static void sneakyThrow(Throwable t) {
  Thread.currentThread().stop(t);
}

Note that the Thread.stop() methods are deprecated, so this code also violates MET02-J. Do not use deprecated or obsolete classes or methods.

Noncompliant Code Example (Bytecode Manipulation)

It is also possible to disassemble a class, remove any declared checked exceptions, and reassemble the class so that checked exceptions are thrown at runtime when the class is used [Roubtsov 2003]. Compiling against a class that declares the checked exception and supplying at runtime a class that lacks the declaration can also result in undeclared checked exceptions. Undeclared checked exceptions can also be produced through crafted use of the sun.corba.Bridge class. All of these practices are violations of this rule.

Risk Assessment

Failure to document undeclared checked exceptions can result in checked exceptions that the caller is unprepared to handle, consequently violating the safety property.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR06-J

Low

Unlikely

High

P1

L3

Related Guidelines

MITRE CWE

CWE-703, Improper Check or Handling of Exceptional Conditions
CWE-248, Uncaught Exception

Bibliography

[API 2014]Thread.stop(Throwable)

[Bloch 2008]

Item 2, "Consider a Builder When Faced with Many Constructor Parameters"

[Goetz 2004b]

 

[JLS 2015]

Chapter 11, "Exceptions"

[Roubtsov 2003]

 

[Schwarz 2004]

 

[Venners 2003]

"Scalability of Checked Exceptions"

 


 

9 Comments

  1. The following compliant solution:

    Refrain from employing code that is capable of throwing undeclared checked exceptions (legitimate or hostile). If the source code can throw them, explicitly document the behavior. Prefer Constructor.newInstance over Class.newInstance. Finally, do not use deprecated methods such as Thread.stop().

    Suggests to me that there are three separate recommendations here.

    I think these two sentences should be in the definition of the definition of the rule:

    Refrain from employing code that is capable of throwing undeclared checked exceptions (legitimate or hostile). If the source code can throw them, explicitly document the behavior.

    Constructor.newInstance over Class.newInstance should not be mentioned here for the first time. I can't tell from reading the text what the issue is.

    Thread.stop() sounds like a different but related guideline. I would think you could create a corresponding compliant solution?

    1. This would indicate that the summary of all the CSs must make it to the introduction, right?

      Do we need to replicate the compliant solution for Thread.stop? Can we just cross reference THI05-J. Do not use Thread.stop() to terminate threads which actually is an alternative to Thread.stop.

      In general, shall we keep NCCEs with no corresponding CSs and (where possible) just generalize the CS to say 'document it when you do it' as was apt for this recommendation?

      1. The introduction only needs to be clear on what the intent of the rule is. This is necessary, among other things, to allow source code analysis tool developers to determine what constitutes a violation of the guideline, and what would is likely to be considered a "false positive" by a developer.

        In general, I would think it is better to pair NCE/CS. This is in general.

        If there are specific cases where one compliant solution addressed multiple NCEs, this is OK. We are trying to preserve some flexibility in how guidelines are written as to not make them overly rigid and proscriptive.

  2. Does a discussion of wrapping checked exceptions belong in this recommendation? It seems to me that the wrapping of exceptions is not directly related to undeclared checked exceptions. Is the intent of including a discussion of wrapped exceptions in this recommendation to provide an alternate strategy to someone who wants to use undeclared checked expressions to avoid many many annoying redundant catch blocks?

    If so, rather than wrapping a specific exception in a more generic exception, designing your exception classes so they inherit from 1 or more more generic exceptions works quite well (this is what we did in the FX system code). If we have exceptions X1, X2, and X3 that inherit from X, we can write method foo() that throws detailed exceptions X1, X2, and X3, but if needed we can just write a catch block to catch exception X when calling foo(), eliminating some unnecessary catch blocks. However, since we have not wrapped X1, X2, or X3 in a more general exception (X1, X3, or X3 are still thrown), if needed the caller of foo() can still choose to catch the specific exceptions.

    1. This guideline does not advocate wrapping checked exceptions in unchecked ones, especially when the exceptional conditions are recoverable. It also discourages undeclared checked exceptions. Some may violate these and use the two techniques to avoid the catch-block clutter. The guideline recommends wrapping a checked exception into a broader checked exception if it is really desired to reduce the number of catch blocks. This enables you to ensure that the caller is prepared to deal with the condition, at least at a higher level.

      Your idea of throwing specific exceptions from the method and catching the exception superclass in the caller is acceptable. However, it is not always the case that X1, X2 and X3 will derive from the same exception class (especially when you are using pre-existing APIs). Even if you are able to use instanceof within the single catch block of the high level caller to check which exception subclass was thrown, it is often not possible to recover at the higher level.

      The exception translation idiom suggests that higher levels should catch lower level exceptions and throw higher level exceptions. Exception chaining is another acceptable way. Recovery may still be impossible. But again, the point of this recommendation is to focus on undeclared checked exceptions and why they should not be used to surprise the caller. Other described mechanisms may be used to reduce the catch-clutter.

      EDIT: The discussion you pointed out is there to limit the practice of using as well as designing future APIs that would favor undeclared checked exceptions.

  3. I believe that Java 1.7's try-with-resources statement might constitute an exception. If such a statement creates an object, then the object's close might throw an exception which is not explicitly declared since the close() statement becomes invisible.

    Not sure if this is actually possible, for two reasons:

    • Only classes which implement AutoCloseable() can cause this problem. The JDK classes that do this are things like Reader, SQLConnection, etc. All these classes throw the same type of exceptions when constructing as destructing. So, for instance, you can't create a Reader w/o catching IOException, and Reader.close() can only throw IOException.
    • Presumably you can create your own AutoCloseable class that throws different exceptions at construction time and at close time. The current compiler catches an undeclared exception from a hidden close(). So theoretically the compiler won't let you get away with it...for now.
    • Please check whether NCE (java.lang.reflect.Class.newInstance()) violates ERR13J and ERR14J anymore and correct the descriptive text accordingly. The second NCE does violate ERR13.
    • This rule is special because there is no "end-all" CS. How about providing a CS that declares the checked exception so that the intent is clear to client code?
      • Please check whether NCE (java.lang.reflect.Class.newInstance()) violates ERR13J and ERR14J anymore and correct the descriptive text accordingly. The second NCE does violate ERR13.

      The NCCE still behaves as advertised. I've updated the text. I think the code samples fall under EX0 of ERR14.

      • This rule is special because there is no "end-all" CS. How about providing a CS that declares the checked exception so that the intent is clear to client code?

      That's because it is a menagerie of techniques to throw undeclared checked exceptions. It's not the only rule that doesn't end in a CS. Personall I think a final CS would be trivial and kinda not worth the effort.

  4. at the last NCCE(Bytecode Manipulation), the second sentence("Compiling against...") says almost the same thing as the first sentence. how about removing it?