...
| Code Block |
|---|
|
// 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 final setAsExceptionReportersetExceptionReporter(ExceptionReporter er) {
er.setExceptionReporter(this);
}
// publicImplementation voidof report(Throwable exception) { /* default implementation */ }
}
|
Noncompliant Code Example (inner class)
| Wiki Markup |
|---|
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 thisThis noncompliant code example, the constructor for uses a different implementation of class {{DefaultExceptionReporter}}. The constructor uses an anonymous inner class to publish a {{filter()}} method. |
| Code Block |
|---|
|
public class AnotherExceptionReporterDefaultExceptionReporter implements ExceptionReporter {
public AnotherExceptionReporterDefaultExceptionReporter(ExceptionReporter er) {
er.setExceptionReporter(new AnotherExceptionReporterDefaultExceptionReporter(er) {
public void report(Throwable t) {
filter(t);
}}
}
);
}
public void filter(Throwable t) {
// FiltersDefault sensitiveimplementations exceptionsof
}
public void report(Throwable exception) {
// Default implementation
}
setExceptionReporter() and report()
}
|
The problem occurs because the this reference of the outer class is published by the inner class so that other threads can see it. If the class is subclassed, the issue described in the previous noncompliant code example resurfaces.
...
| Code Block |
|---|
|
public class AnotherExceptionReporterDefaultExceptionReporter implements ExceptionReporter {
private final AnotherExceptionReporterDefaultExceptionReporter defaultER;
private AnotherExceptionReporterDefaultExceptionReporter(ExceptionReporter excr) {
defaultER = new AnotherExceptionReporter(excr) {
public void report(Throwable t) {
filter(t);
}
defaultER = new };DefaultExceptionReporter(excr) {
}
public staticvoid AnotherExceptionReporter newInstancereport(ExceptionReporterThrowable excrt) {
AnotherExceptionReporter der = new AnotherExceptionReporterfilter(excrt);
excr.setExceptionReporter(der.defaultER);}
return der};
}
public static voidDefaultExceptionReporter filternewInstance(ThrowableExceptionReporter texcr) {
//DefaultExceptionReporter Filtersder sensitive= exceptionsnew DefaultExceptionReporter(excr);
}
public void report(Throwable exception) { excr.setExceptionReporter(der.defaultER);
return der;
}
// Default implementations implementationof
setExceptionReporter() and }report()
}
|
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).
...