...
- Input validation (for example, method parameters)
- Reordering the logic so that the code capable of resulting in the exceptional condition, executes before the code that modifies the object doesexecutes
- Through the use of rollbacks, upon intercepting a failure notification
- Performing required operations on a temporary copy and committing changes to the original object, after their successful completion
...
This noncompliant code example shows a Dimensions
class that contains three internal attributes, the length
, width
and height
of a rectangular box. The getVolumePackage()
method is designed to return the total volume required to hold the box, after accounting for packaging material which further adds a further 2 units to the dimensions of each side. Non positive values of the dimensions of the box (exclusive of packaging material) are rejected during the input validation. Also, the weight
of the object is passed in as a parameter an argument and cannot be more than 20 units. Consider the case where the weight
is more than 20 units (21 units, here). This causes an IllegalArgumentException
which is intercepted by the custom error reporter. While the logic restores the object's original state in the absence of this exception, it omits doing the same from within the catch
block. This violates the object's invariants such that when getVolumePackage()
is called for the second time, it produces incorrect results.
Code Block | ||
---|---|---|
| ||
class Dimensions { private int length; private int width; private int height; public Dimensions(int length, int width, int height) { this.length = length; this.width = width; this.height = height; } protected int getVolumePackage(int weight) { length += 2; width += 2; height += 2; try { if(length <= 02 || width <= 02 || height <= 02 || weight <= 0 || weight >= 20) throw new IllegalArgumentException(); int volume = length * width * height; // 12 * 12 * 12 = 1728 length -=2; width -= 2; height -= 2; // revertRevert back return volume; } catch(Throwable t) { MyExceptionReporter mer = new MyExceptionReporter(); mer.report(t); // sanitizeSanitize return -1; // nonNon-positive error code } } public static void main(String[] args) { Dimensions d = new Dimensions(10, 10, 10); System.out.println(d.getVolumePackage(21)); // printsPrints -1 (error) System.out.println(d.getVolumePackage(19)); // printsPrints 2744 instead of 1728 } } |
Compliant Solution
...
Code Block | ||
---|---|---|
| ||
// ... } catch(Throwable t) { MyExceptionReporter mer = new MyExceptionReporter(); mer.report(t); // sanitizeSanitize length -=2; width -= 2; height -= 2; // revertRevert back return -1; } |
Compliant Solution
...
Code Block | ||
---|---|---|
| ||
protected int getVolumePackage(int weight) { try { if(length <= 0 || width <= 0 || height <= 0 || weight <= 0 || weight > 20) throw new IllegalArgumentException(); // validateValidate first length += 2; width += 2; height += 2; int volume = length * width * height; length -=2; width -= 2; height -= 2; return volume; } catch(Throwable t) { MyExceptionReporter mer = new MyExceptionReporter(); mer.report(t); // sanitizeSanitize return -1; } } |
Risk Assessment
...