Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: cleaned up code

...

Code Block
bgColor#FFcccc
// Interface ExceptionReporter
public interface ExceptionReporter {
  public void setExceptionReporter(ExceptionReporter er);
  public void report(Throwable exception);
}

// Class DefaultExceptionReporter
public class DefaultExceptionReporter implements ExceptionReporter {
  public DefaultExceptionReporter(ExceptionReporter er) {
    // Carry out initialization 
    // Incorrectly publishes the "this" reference
    er.setExceptionReporter(this);
  }

  public final void setExceptionReporter(ExceptionReporter er) { 
    // Sets the reporter 
  }

  public void report(Throwable exception) { /* default implementation */ }
}

...

Compliant Solution

This compliant solution defines a method setReporter() in class MyExceptionReporter. The method explicitly calls the superclass's setExceptionReporter() method, publishing a reference to its own Class object. It is not permissible to publish the reference in the constructor for MyExceptionReporter for reasons noted earlier in the noncompliant code example. Other code remains unchangedtakes the publication out of the DefaultExceptionReporter constructor, and adds a setExceptionReporter() method that is expected to be called after a subclass is constructed.

Code Block
bgColor#ccccff

public class MyExceptionReporter extends DefaultExceptionReporter {
  // ...
// Class DefaultExceptionReporter
public class DefaultExceptionReporter implements ExceptionReporter {
  public DefaultExceptionReporter(ExceptionReporter er) {
    // Carry out initialization 
  }

  // Registers this exception reporter. 
  // Should be called after constructing a new ExceptionReporter object
  public voidfinal setReportersetAsExceptionReporter(ExceptionReporter er) {
    superer.setExceptionReporter(this);
  this);
  }

  public void report(Throwable exception) { /* default implementation */ }
}

Because, setReporter() is an instance method, it cannot be invoked until the subclass's initialization has finished.

Noncompliant Code Example (inner class)

...




h2. Noncompliant Code Example (inner class)

It is possible for the {{this}} reference to implicitly get leaked outside the scope \[[Goetz 02|AA. Java References#Goetz 02]\]. Consider inner classes that maintain a copy of the {{this}} reference of the outer object. In this noncompliant code example, the constructor for class {{DefaultExceptionReporter}} uses an anonymous inner class to publish a {{filter()}} method. 

...



{code
:bgColor
=#FFcccc
}
public class DefaultExceptionReporterAnotherExceptionReporter implements ExceptionReporter {
  public DefaultExceptionReporterAnotherExceptionReporter(ExceptionReporter er) {
    er.setExceptionReporter(new DefaultExceptionReporterAnotherExceptionReporter(er) {
        public void report(Throwable t) {
          filter(t);
        }
      }
    );
  }

  public void filter(Throwable t) { 
    // Filters sensitive exceptions 
  }

  public void setExceptionReporter(ExceptionReporter er) { 
    // Sets the reporter 
  }

  public void report(Throwable exception) { 
    // Default implementation 
  }
}

...

Code Block
bgColor#ccccff
public class DefaultExceptionReporterAnotherExceptionReporter implements ExceptionReporter {
  private final DefaultExceptionReporterAnotherExceptionReporter defaultER;

  private DefaultExceptionReporterAnotherExceptionReporter(ExceptionReporter excr) {
    defaultER = new DefaultExceptionReporterAnotherExceptionReporter(excr) {
      public void report(Throwable t) {
        filter(t);
      } 
    };
  }
 
  public static DefaultExceptionReporterAnotherExceptionReporter newInstance(ExceptionReporter excr) {
    DefaultExceptionReporterAnotherExceptionReporter der = new DefaultExceptionReporterAnotherExceptionReporter(excr);
    excr.setExceptionReporter(der.defaultER);
    return der;
  }

  public void setExceptionReporterfilter(ExceptionReporterThrowable ert) { }

    public void filter(Throwable t) {// Filters sensitive exceptions 
  }

  public void report(Throwable exception) { 
    // Default implementation 
  }
}

Because the constructor is private, untrusted code cannot create instances of the class, prohibiting the this reference from escaping. Using a public static factory method to create new instances also protects against publication of partially initialized objects (CON26-J. Do not publish partially initialized objects).

...

This noncompliant code example starts a thread from within the constructor.

Code Block
bgColor#FFcccc
class Routine implements Runnable {
  public SomeConstructorRoutine() {
    Thread thread = new MyThreadThread(this);
    thread.start();
  }

Wiki Markup
This allows the new thread to access the {{this}} reference of the current object \[[Goetz 02|AA. Java References#Goetz 02], [Goetz 06|AA. Java References#Goetz 06]\].

Compliant Solution



  public void run() {
    // thread execution code
  }
}

Wiki Markup
InThis thisallows compliantthe solution, even though the thread is created in the constructor, it is not started until its {{start()}} method is called from method {{startThread()}}new thread to access the {{this}} reference of the current object \[[Goetz 02|AA. Java References#Goetz 02], [Goetz 06|AA. Java References#Goetz 06]\]].

Compliant Solution (thread)

In this compliant solution, the thread execution is done in a public method, rather than in the constructor.

Code Block
bgColor#ccccff
class Routine implements Runnable {
  public SomeConstructorvoid startThread() {
    Thread thread = new MyThreadThread(this);
    thread.start();
  }

  public void startThreadrun() {
  thread.start();  // thread execution code
  }
}

Risk Assessment

Allowing the this reference to escape may result in improper initialization and runtime exceptions.

...