Wiki Markup |
---|
Method chaining is |
...
Method chaining should not be used in a multi-threaded environment, because a set of chained methods is non-atomic, and it is easy to violate CON07-J. Do not assume that a group of calls to independently atomic methods is atomic.
Noncompliant Code Example
Method chaining is useful for building an object and setting its optional fields. However, in a multi-threaded environment, a thread may observe inconsistent values in the object's fields if it allows method chaining. This noncompliant code example shows the unsafe Javabeans pattern.
Code Block | ||
---|---|---|
| ||
a convenience mechanism that allows multiple method invocations on the same object to occur in a single statement. Classes that support method chaining provide several setter methods that return the {{this}} reference. Method chaining should not be used in a multi-threaded environment because chained invocations of a set of methods is non-atomic and consequently, noncompliant with [CON07-J. Do not assume that a group of calls to independently atomic methods is atomic]. h2. Noncompliant Code Example Method chaining is useful for building an object and setting its optional fields. However, in a multi-threaded environment, a thread may observe a shared field to contain inconsistent values. This noncompliant code example shows the Javabeans pattern which is not safe for multithreaded use. {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: final USCurrency currency = new USCurrency(); new Thread(new Runnable() { public void run() { USCurrency currency = new USCurrency().currency.setQuarters(1).setDimes(1); } }).start(); new Thread(new Runnable() { public void run() { USCurrency currency = new USCurrency().currency.setQuarters(2).setDimes(2); } }).start(); {code} The Javabeans pattern uses a no-argument constructor along with a series of parallel setter methods to build an object. This pattern is not thread-safe and can lead to inconsistent object state. In this example |
...
Compliant Solution
...
, a client thread that constructs a {{USCurrency}} object may find the object to contain one quarter and two dimes. h2. Compliant Solution This compliant solution uses the variant of the Builder pattern \[[Gamma 95|AA. Java References#Gamma 95]\] |
...
suggested by Bloch \[[Bloch 08|AA. Java References#Bloch 08]\] to ensure thread safety and atomicity of object creation. |
...
{code | ||
:bgColor | =#ccccff | } final class USCurrency { private final int quarters = 0; private final int dimes = 0; private final int nickels = 0; private final int pennies = 0; privatepublic 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 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: USCurrency currency = USCurrency.Builder().setQuarters(3(1).setDimes(1).build(); USCurrency currency = USCurrency.Builder().setQuarters(2).setDimes(32).build(); |
The idea is to call the constructor with the required parameters and obtain a builder object. Each optional parameter can be set using setters on the builder. The object construction concludes with the invocation of the build()
method. This also has the effect of making the class Currency
immutable; consequently it is also thread-safe.
If input needs to be validated, make sure that the values are copied from the builder class to the containing class's fields prior to checking. The builder class does not violate SCP03-J. Do not expose sensitive private members of the outer class from within a nested class because it maintains a copy of the variables defined in the scope of the containing class. These take precedence and as a result do not break encapsulation.
If the number of fields is small, it is better to synchronize the setter methods instead of using this design pattern. But take care to ensure that the setter methods provide the required degree of atomicity, see CON07-J. Do not assume that a group of calls to independently atomic methods is atomic for more information.
Exceptions
EX1: A class may employ method chaining in a multi-threaded environment as long as it documents this fact. Consequently client code must provide client-side locking in order to preserve the thread-safety of its code.
Code Block | ||
---|---|---|
| ||
{code} The {{Builder}} constructor is called with the _required_ arguments (if any) to obtain a _builder_ object. The _optional_ parameters are set using the setter methods on the builder. The object construction concludes with the invocation of the {{build()}} method. This also makes the class {{Currency}} immutable, and consequently, thread-safe. If input needs to be validated, make sure that the values are copied from the builder class to the containing outer class's fields prior to the validation. The builder class does not violate [SCP03-J. Do not expose sensitive private members of the outer class from within a nested class] because it maintains a copy of the variables defined in the scope of the containing class. These take precedence and as a result, do not break encapsulation. If the number of fields is small, it is better to synchronize the setter methods instead of using this design pattern. But care must be taken to ensure that the setter methods provide the required degree of atomicity. (see [CON07-J. Do not assume that a group of calls to independently atomic methods is atomic] for more information.) h2. Exceptions *EX1*: A class may use method chaining in a multithreaded environment if it sufficiently documents this fact. Client code must externally use some locking to ensure that the method calls are thread-safe. {mc} I don't think this class is necessary. (to avoid bloat; most readers would know what we are talking about by now) {code:bgColor=#ccccff} // This class is not thread-safe!. A client must provide locking on any // USCurrency object in a multi-threaded environment!. 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: final USCurrency currency = new USCurrency(); final Object lock = new Object(); new Thread(new Runnable() { public void run() { synchronized (lock) { currency.setQuarters(1).setDimes(1); } } }).start(); new Thread(new Runnable() { public void run() { synchronized (lock) { currency.setQuarters(2).setDimes(2); } } }).start(); {code} This code achieves thread-safety by having the client code perform all modification of the {{USCurrency}} object only while a {{lock}} is held |
...
Risk Assessment
Using implementations of method chaining that are not thread-safe can lead to non-deterministic behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON30- J | low | unlikely | high | P1 | L1 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
...
. {mc} h2. Risk Assessment Using implementations of method chaining that are not thread-safe can lead to non-deterministic behavior. || Rule || Severity || Likelihood || Remediation Cost || Priority || Level || | CON30- J | low | unlikely | high | {color:green}{*}P1{*}{color} | {color:green}{*}L1{*}{color} | h3. Automated Detection TODO h3. Related Vulnerabilities Search for vulnerabilities resulting from the violation of this rule on the [CERT website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FIO38-J]. h2. References \[[API 06|AA. Java References#API 06]\] \[[Bloch 08|AA. Java References#Bloch 08]\] Item 7, Avoid finalizers |
...
---- [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|FIO36-J. Do not create multiple buffered wrappers on an |
...
InputStream] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|09. Input Output (FIO)] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|09. Input Output (FIO)]
|