Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Method chaining is a technique that defines several methods that return the this reference of the current object. It is a convenience convenient mechanism that allows multiple method invocations on the same object to occur , in a single statement. Each method invocation returns this which is then used to invoke the next method in the chain. Many objects provide setter methods that return this, enabling the user to chain multiple setter methods together.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.

Although the methods used in method chaining can be atomic, the chain they comprise is inherently nonatomic. 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 shown in VNA03Method 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 a useful design pattern for building an object and setting its optional fields. However, in a multi-threaded environmentA 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 in the object's fields if it allows method chaining. This noncompliant code example shows the unsafe Javabeans pattern.JavaBeans pattern, which is not thread-safe:

Code Block
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();

    //...
  }
}

The Javabeans JavaBeans pattern uses a no-argument constructor along with and a series of parallel setter methods to build an object. This pattern is not thread-safe and can lead to inconsistent object state when the object is modified concurrently. In this noncompliant code example code, the currency object might wind up with 1 quarter and 2 dimes!

Compliant Solution

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.

Compliant Solution

This compliant solution uses the variant of the Builder pattern [Gamma 1995], suggested by Bloch [Bloch 2008], to ensure the thread-safety and atomicity of object creation. Wiki MarkupThis compliant solution uses the variant of the Builder pattern \[[Gamma 95|AA. Java References#Gamma 95]\] that is suggested by Bloch \[[Bloch 08|AA. Java References#Bloch 08]\] to ensure thread safety and atomicity of object creation.

Code Block
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 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:
USCurrencyclass currencyExampleClientCode = USCurrency.Builder().setQuarters(3).setDimes(3).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
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();

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

 {

  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();

    //...
  }
}

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 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 OBJ06-J. Defensively copy mutable inputs and mutable internal components for more information). The Builder class also complies with OBJ08-J. Do not expose 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.

Risk Assessment

Using method chaining in multithreaded environments without performing external locking can lead to nondeterministic Using implementations of method chaining that are not thread-safe can lead to non-deterministic behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON30VNA04-J

low Low

unlikely Probable

high Medium

P1 P4

L1

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[API 06|AA. Java References#API 06]\] 
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 7, Avoid finalizers

L3

Bibliography

[API 2014]

 

[Bloch 2008]

Item 2, "Consider a Builder When Faced with Many Constructor Parameters"

 

...

Image Added Image Added Image AddedFIO36-J. Do not create multiple buffered wrappers on an InputStream      09. Input Output (FIO)      09. Input Output (FIO)