| Wiki Markup |
|---|
According to the Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\], section 15.8.3 {{this}}: |
When used as a primary expression, the keyword
thisdenotes a value that is a reference to the object for which the instance method was invoked (§15.12), or to the object being constructed. The type ofthisis the classCwithin which the keywordthisoccurs. At run time, the class of the actual object referred to may be the classCor any subclass ofC.
The this reference is said to have escaped when it is made available beyond its current scope. Common ways by which the this reference can escape include:
- Returning
thisfrom a non-private nonprivate method - Passing
thisas an argument to an alien method - Publishing
thisfrom the constructor of an object under construction - Publishing
thissuch that pieces of code beyond its current scope can obtain its reference - Calling a non-final method from a constructor (MET04-J. Ensure that constructors do not call overridable methods)
- Overriding the finalizer of a non-final class and obtaining the
thisreference of a partially constructed instance, when the construction of the object ceases (OBJ04-J. Do not allow partially initialized objects to be accessed) - Passing internal object state to an alien method and consequently, exposing the
thisreference of internal objects
This guideline focuses on the potential consequences of this escaping during object construction including race conditions and improper initialization. For example, declaring a field final ensures that all threads will see it fully initialized only when the this reference does not escape during the corresponding object's construction. The guideline CON26-J. Do not publish partially-constructed objects discusses the guarantees provided by various mechanisms for safe publication and relies on conformance to this guideline. In general, it is important to detect cases where the this reference can leak out beyond the scope of the current context. In particular, be careful when using public variables and methods should be carefully scrutinized.
Noncompliant code Example (publish before initialization)
This noncompliant code example publishes the this reference before initialization has concluded, by storing it in a public static volatile class field. Consequently, other threads may obtain a partially initialized Publisher instance.
| Code Block | ||
|---|---|---|
| ||
class Publisher {
public static volatile Publisher pub; // Also noncompliant if field is nonvolatile
int num;
Publisher(int number) {
pub = this;
// Initialization
this.num = number;
// ...
}
}
|
Also, if the object construction or initialization initialization (and consequently, its construction) depends on a security check within the constructor, the security check will be bypassed if an untrusted caller obtains the partially initialized instance (see OBJ04-J. Do not allow partially initialized objects to be accessed for more details).
...
| Code Block | ||
|---|---|---|
| ||
class Publisher {
public static Publisher pub;
int num;
Publisher(int number) {
// Initialization
this.num = number;
// ...
pub = this;
}
}
|
Because, the field is nonvolatile and nonfinal, the statements within the constructor can be reordered by the compiler in such a way that the this reference is published before the initialization statements are executed.
Compliant Solution
This compliant solution declares the pub field as volatile and reduces the accessibility of the static class field to package-private so that untrusted callers beyond the current package cannot obtain the this instance. More importantly, the constructor publishes the this reference after initialization has concluded.
...
If the pub field is not declared as volatile initialization statements may be reordered. The Java compiler does not allow declaring the static pub field as final in this case.
Noncompliant Code Example (
...
handlers)
This noncompliant code example defines the ExceptionReporter interface that is implemented by the class ExceptionReporters DefaultExceptionReporter. This class is useful for reporting exceptions after filtering out any sensitive information (EXC01-J. Use a class dedicated to reporting exceptions). The ExceptionReporters DefaultExceptionReporter constructor, incorrectly prematurely publishes the this reference before construction of the object has concluded. This occurs in the last statement in of the constructor (er.setExceptionReporter(this)) which sets the exception reporter. Because it is the last statement of the constructor, this may be misconstrued as benign.
| Code Block | ||
|---|---|---|
| ||
// Interface ExceptionReporter
public interface ExceptionReporter {
public void setExceptionReporter(ExceptionReporter er);
public void report(Throwable exception);
}
// Class ExceptionReportersDefaultExceptionReporter
public class ExceptionReportersDefaultExceptionReporter implements ExceptionReporter {
public ExceptionReportersDefaultExceptionReporter(ExceptionReporter er) {
// Carry out initialization
// Incorrectly publishes the "this" reference
er.setExceptionReporter(this);
}
public final void reportsetExceptionReporter(ThrowableExceptionReporter exceptioner) { /* default implementation */
// Sets the reporter
}
public final void setExceptionReporterreport(ExceptionReporterThrowable erexception) {
/* default implementation *// Sets the reporter
}
}
// Class MyExceptionReporter derives from ExceptionReportersDefaultExceptionReporter
public class MyExceptionReporter extends ExceptionReportersDefaultExceptionReporter {
private final Logger logger;
public MyExceptionReporter(ExceptionReporter er) {
super(er); // Calls superclass's constructor
logger = Logger.getLogger("com.organization.Log");
}
public void report(Throwable t) {
logger.log(Level.FINEST,"Loggable exception occurred",t);
}
}
|
The class MyExceptionReporter subclasses ExceptionReporters DefaultExceptionReporter with the intent of adding a logging mechanism that logs critical messages before an exception is reported. Its constructor invokes the superclass DefaultExceptionReporter's constructor (a mandatory first step) which publishes the exception reporter before the initialization of the subclass has concluded, setting the exception handler. Note that the subclass initialization consists of obtaining an instance of the default logger. Publishing the exception reporter is equivalent to setting it so that it can receive and handle exceptions from that point onwards.
If any exception occurs before the call to Logger.getLogger() in the subclass, it is not logged. Instead, a NullPointerException is generated which may itself be consumed by the reporting mechanism.
This erroneous behavior results from the race condition between an oncoming exception and the initialization of the subclass. If the exception comes too soon, it finds the subclass in a compromised state. This behavior is especially counter intuitive because logger is declared final and is not expected to contain an unintialized value.
This issue can also occur when a listener is prematurely published. Consequently, it will start receiving event notifications even before the subclass's initialization has concluded.
Compliant Solution
This compliant solution declares the defines a method setReporter() method in class MyExceptionReporter. It 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.
| Code Block | ||
|---|---|---|
| ||
public class MyExceptionReporter extends ExceptionReportersDefaultExceptionReporter { // ... public void setReporter(ExceptionReporter er) { super.setExceptionReporter(this); } } |
Because, setReporter() is an instance method, it cannot be invoked until the subclass's initialization has finished.
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 this noncompliant code example, the constructor for class {{BadExceptionReporter}} uses an anonymous inner class to publish a {{filter()}} method. 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 first noncompliant code example resurfaces. |
| Code Block | ||
|---|---|---|
| ||
public class BadExceptionReporter implements ExceptionReporter {
public BadExceptionReporter(ExceptionReporter er) {
er.setExceptionReporter(new ExceptionReportersDefaultExceptionReporter(er) {
public void report(Throwable t) {
filter(t);
}
});
}
public void filter(Throwable t) {
// Filters sensitive exceptions
}
public void reportsetExceptionReporter(ThrowableExceptionReporter exceptioner) {
// DefaultSets the implementationreporter
}
public void setExceptionReporterreport(ExceptionReporterThrowable erexception) {
// SetsDefault the reporterimplementation
}
}
|
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.
Compliant Solution
| Wiki Markup |
|---|
A {{private}} constructor alongside a {{public}} factory method can be used to safely publish the {{filter()}} method from within the constructor \[[Goetz 06|AA. Java References#Goetz 06]\]. |
| Code Block | ||
|---|---|---|
| ||
public class GoodExceptionReporter implements ExceptionReporter {
private final ExceptionReportersDefaultExceptionReporter er;
private GoodExceptionReporter(ExceptionReporter excr) {
er = new ExceptionReportersDefaultExceptionReporter(excr) {
public void report(Throwable t) {
filter(t);
}
};
}
public static GoodExceptionReporter newInstance(ExceptionReporter excr) {
GoodExceptionReporter ger = new GoodExceptionReporter(excr);
excr.setExceptionReporter(ger.er);
return ger;
}
public void filtersetExceptionReporter(ThrowableExceptionReporter ter) { }
public void reportfilter(Throwable exceptiont) { }
public void setExceptionReporterreport(ExceptionReporterThrowable erexception) { }
}
|
Noncompliant Code Example (thread)
This noncompliant code example starts a thread from within the constructor. Wiki Markup
| Code Block | ||
|---|---|---|
| ||
public someConstructor() {
thread = new MyThread(this);
thread.start();
}
|
| Wiki Markup |
|---|
noncompliant code example starts a thread from within the constructor. 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]\]. |
...
| bgColor | #FFcccc |
|---|
...
Compliant Solution
| Wiki Markup |
|---|
In this compliant solution, even though the thread is created in the constructor, it is not started until its {{start()}} method is called from method {{startThread()}} \[[Goetz 02|AA. Java References#Goetz 02], [Goetz 06|AA. Java References#Goetz 06]\]. |
...