...
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 | ||
|---|---|---|
| ||
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 | ||
|---|---|---|
| ||
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 |
...