Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: edits

...

Several design patterns exist for building an object and setting its optional fields. However, not all of them provide initialization safety. That is, in that, a thread may observe the object before its construction is over. This noncompliant code example shows the unsafe Javabeans pattern:.

Code Block
bgColor#FFcccc
final class Currency {
  // totalTotal amount requested (requiredmandatory fields)
  private int dollars = -1; // initializeInitialize to default value
  private int cents = -1;   // initializeInitialize to default value
  // changeChange requested, denomination (optional fields)
  private int quarters = 0;
  private int dimes = 0;
  private int nickels = 0;
  private int pennies = 0;
  public Currency() {} // no argument constructor

  // setterSetter methods 
  public Currency setDollar(int amount) { 
    dollars = amount;
    return this;
  }

  public Currency setCents(int amount) { 
    cents = amount;
    return this; 
  }

  public Currency setQuarters(int quantity) { 
    quarters = quantity; 
    return this;
  } 
  public Currency setDimes(int quantity) { 
    dimes = quantity; 
    return this;
  }
  
  public Currency setNickels(int quantity) { 
    nickels = quantity;
    return this;
  }
  
  public Currency setPennies(int quantity) { 
    pennies = quantity;
    return this;
  }
}

// Client code:
Currency currUSD = new Currency();
currUSD.setDollar(10).setCents(50).setQuarters(42);

...

Wiki Markup
This compliant solution uses the Builder pattern's \[[Gamma 95|AA. Java References#Gamma 95]\] variant 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 Currency {
  // totalTotal amount requested (requiredmandatory fields)
  private final int dollars;
  private final int cents;
  // changeChange requested, denomination (optional fields)
  private final int quarters;
  private final int dimes;
  private final int nickels;
  private final int pennies;
  
  // Static class member 
  private Currency(Builder builder) {
    dollars = builder.dollars;
    cents = builder.cents;
   
    quarters = builder.quarters;
    dimes = builder.dimes;
    nickels = builder.nickels;
    pennies = builder.pennies;
  }

  // Static class member 
  public static class Builder {
    private final int dollars;
    private final int cents;
    private int quarters = 0;
    private int dimes = 0;
    private int nickels = 0;
    private int pennies = 0;
	 
    public Builder(int dollars, int cents) {
      this.dollars = dollars;
      this.cents = cents;
    }
    public Builder quarters(int quantity) {
      quarters = quantity;  
      return this; 
    }
    public Builder dimes(int quantity) {
      dimes = quantity; 
      return this;	 
    }
    public Builder nickles(int quantity) {
      nickels = quantity; 
      return this;	 
    }
    public Builder pennies(int quantity) {
      pennies = quantity; 
      return this;	 
    }
    public Currency build() {
      return new Currency(this); 	 
    }
  }
}

// Client code:
Currency USD = new Currency.Builder(10,50).quarters(42).build();

...

If the number of fields is small, it is better to synchronize the setter methods instead of using this design pattern.

Risk Assessment

Using thread-unsafe implementations of method chaining that are not thread-safe can lead to undefined non-deterministic behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON30- J

low

unlikely

high

P1

L1

...