...
| Code Block |
|---|
|
// 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 |
|---|
|
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 |
|---|
|
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 |
|---|
|
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 |
|---|
|
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.
...