Method chaining is a convenience mechanism that allows multiple method invocations on the same object to occur in a single statement. A method chaining implementation consists of a series of methods that return the {{this}} reference. This implementation allows a caller to invoke methods in a chain by performing the next method invocation on the return value of the previous method in the chain.
While the methods used in method chaining can be atomic, the chain they comprise is inherently non-atomic. Consequently, callers of methods that are involved in method chaining must provide sufficient locking to guarantee that the entire chain of invocations is atomic, as illustrated in guidelinerule [VNA03-J. Do not assume that a group of calls to independently atomic methods is atomic].
h2. Noncompliant Code Example
Method chaining is a useful design pattern for building an object and setting its optional fields. A class that supports method chaining provides several setter methods that each return the {{this}} reference. However, if accessed concurrently, a thread may observe shared fields to contain inconsistent values. This noncompliant code example shows the JavaBeans pattern, which fails to be thread-safe.
{code:bgColor=#FFcccc}
final class USCurrency {
// Change requested, denomination (optional fields)
private int quarters = 0;
private int dimes = 0;
private int nickels = 0;
private int pennies = 0;
public USCurrency() {}
// Setter methods
public USCurrency setQuarters(int quantity) {
quarters = quantity;
return this;
}
public USCurrency setDimes(int quantity) {
dimes = quantity;
return this;
}
public USCurrency setNickels(int quantity) {
nickels = quantity;
return this;
}
public USCurrency setPennies(int quantity) {
pennies = quantity;
return this;
}
}
// Client code:
class exampleClientCode{
private final USCurrency currency = new USCurrency();
// ...
public exampleClientCode(){
Thread t1 = new Thread(new Runnable() {
@Override public void run() {
currency.setQuarters(1).setDimes(1);
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override public void run() {
currency.setQuarters(2).setDimes(2);
}
});
t2.start();
//...
}
}
{code}
The JavaBeans pattern uses a no-argument constructor and a series of parallel setter methods to build an object. This pattern fails to be thread-safe and can lead to inconsistent object state when the object is modified concurrently. In this noncompliant code example, the client constructs a {{USCurrency}} object and starts two threads that use method chaining to set the optional values of the {{USCurrency}} object. This example code might result in the {{USCurrency}} instance being left in an inconsistent state, for example, with two quarters and one dime or one quarter and two dimes.
h2. Compliant Solution
This compliant solution uses the variant of the Builder pattern \[[Gamma 1995|AA. Bibliography#Gamma 95]\], suggested by Bloch \[[Bloch 2008|AA. Bibliography#Bloch 08]\], to ensure the thread safety and atomicity of object creation. {mc} What does this mean? It can be accessible to any number of threads ~DM => The method chaining is actually constrained to the {{USCurrency.Builder}} class which is only accessible from a single thread. {mc}
{code:bgColor=#ccccff}
final class USCurrency {
private final int quarters;
private final int dimes;
private final int nickels;
private final int pennies;
public USCurrency(Builder builder) {
this.quarters = builder.quarters;
this.dimes = builder.dimes;
this.nickels = builder.nickels;
this.pennies = builder.pennies;
}
// Static class member
public static class Builder {
private int quarters = 0;
private int dimes = 0;
private int nickels = 0;
private int pennies = 0;
public static Builder newInstance() {
return new Builder();
}
private Builder() {}
// Setter methods
public Builder setQuarters(int quantity) {
this.quarters = quantity;
return this;
}
public Builder setDimes(int quantity) {
this.dimes = quantity;
return this;
}
public Builder setNickels(int quantity) {
this.nickels = quantity;
return this;
}
public Builder setPennies(int quantity) {
this.pennies = quantity;
return this;
}
public USCurrency build() {
return new USCurrency(this);
}
}
}
// Client code:
class exampleClientCode{
private volatile USCurrency currency;
// ...
public exampleClientCode(){
Thread t1 = new Thread(new Runnable() {
@Override public void run() {
currency = USCurrency.Builder.newInstance().setQuarters(1).setDimes(1).build();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override public void run() {
currency = USCurrency.Builder.newInstance().setQuarters(2).setDimes(2).build();
}
});
t2.start();
//...
}
}
{code}
The {{Builder.newInstance()}} factory method is called with any required arguments to obtain a {{Builder}} instance. The optional parameters are set using the setter methods of the builder. The object construction concludes with the invocation of the {{build()}} method. This pattern makes the {{USCurrency}} class immutable and, consequently, thread-safe.
Note that the {{currency}} field cannot be declared final because it is assigned a new immutable object. It is, however, declared volatile in compliance with guidelinerule [VNA01-J. Ensure visibility of shared references to immutable objects].
When input must be validated, ensure that the values are defensively copied prior to validation. (See guidelinerule [OBJ14-J. Defensively copy mutable inputs and mutable internal components] for more information.) The {{builder}} class complies with guidelinerule [OBJ13-J. Do not expose sensitive private members of an outer class from within a nested class] because it maintains a copy of the variables defined in the scope of the containing class. The private members within the nested class take precedence and, as a result, maintain encapsulation.
h2. Risk Assessment
Using method chaining in multithreaded environments without performing external locking can lead to nondeterministic behavior.
|| Guideline || Severity || Likelihood || Remediation Cost || Priority || Level ||
| VNA04-J | low | probable | medium | {color:green}{*}P4{*}{color} | {color:green}{*}L3{*}{color} |
h3. Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guidelinerule on the [CERT website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO38-J].
h2. Bibliography
\[[API 2006|AA. Bibliography#API 06]\]
\[[Bloch 2008|AA. Bibliography#Bloch 08]\] Item 2: "Consider a builder when faced with many constructor parameters"
----
[!The CERT Oracle Secure Coding Standard for Java^button_arrow_left.png!|VNA03-J. Do not assume that a group of calls to independently atomic methods is atomic] [!The CERT Oracle Secure Coding Standard for Java^button_arrow_up.png!|07. Visibility and Atomicity (VNA)] [!The CERT Oracle Secure Coding Standard for Java^button_arrow_right.png!|VNA05-J. Ensure atomicity when reading and writing 64-bit values]
|