clone() Method Without super.clone()
Description
clone() Method Without super.clone() is a programming error in Java where a class implements the clone() method but fails to call super.clone() when creating the cloned object. According to Java's cloning convention, all clone() implementations should obtain the new object by calling super.clone(). This ensures that the clone chain properly invokes Object.clone(), which creates a new instance of the correct runtime type. When a class violates this convention by using constructors instead of super.clone(), any subclass's clone() method will return an object of the wrong type—the parent class type instead of the actual subclass type.
Risk
Failing to call super.clone() leads to subtle but serious bugs in class hierarchies. When subclasses rely on the parent's clone() method, they receive objects of the parent type, not their own type. This causes ClassCastException at runtime when the clone is cast to the expected subclass type. The error may not manifest until subclasses are created, making it a latent defect. Applications experience unexpected runtime failures that are difficult to trace back to the improper clone implementation. Additionally, the cloned objects may have incorrect behavior if subclass-specific fields are not properly initialized.
Solution
Always call super.clone() as the first step in clone() implementations. The Object.clone() method, reached through the super.clone() chain, creates a shallow copy of the correct runtime type. After obtaining the clone, perform any necessary deep copying of mutable fields. Alternatively, consider avoiding clone() altogether and use copy constructors or static factory methods, which are more explicit and less error-prone. If using clone(), ensure the class implements Cloneable interface to avoid CloneNotSupportedException. Document the cloning behavior clearly for subclasses.
Common Consequences
| Impact | Details |
|---|---|
| Integrity | Scope: Integrity Unexpected State - Cloned objects have the wrong type, causing type mismatches and incorrect behavior in class hierarchies. |
| Other | Scope: Other Quality Degradation - Applications fail at runtime with ClassCastException when subclasses attempt to use the flawed clone implementation. |
Example Code
Vulnerable Code
// Vulnerable: clone() without super.clone()
public class Kibitzer implements Cloneable {
private String name;
private int rating;
public Kibitzer(String name, int rating) {
this.name = name;
this.rating = rating;
}
// Vulnerable: Using constructor instead of super.clone()
@Override
public Object clone() throws CloneNotSupportedException {
// Wrong! Creates Kibitzer, not subclass type
return new Kibitzer(this.name, this.rating);
}
public String getName() { return name; }
public int getRating() { return rating; }
}
// Subclass that inherits broken clone
public class FancyKibitzer extends Kibitzer {
private String title;
public FancyKibitzer(String name, int rating, String title) {
super(name, rating);
this.title = title;
}
// This clone() will fail!
@Override
public Object clone() throws CloneNotSupportedException {
// Calls parent's clone which returns Kibitzer, not FancyKibitzer!
FancyKibitzer copy = (FancyKibitzer) super.clone(); // ClassCastException!
// title field never gets copied
return copy;
}
public String getTitle() { return title; }
}
// Vulnerable: More complex example with mutable fields
public class Person implements Cloneable {
private String name;
private Date birthDate;
private List<String> nicknames;
// Vulnerable: Constructor-based clone
@Override
public Object clone() {
// Wrong approach - breaks subclass cloning
Person copy = new Person();
copy.name = this.name;
copy.birthDate = new Date(this.birthDate.getTime());
copy.nicknames = new ArrayList<>(this.nicknames);
return copy;
}
}
public class Employee extends Person {
private String employeeId;
private Department department;
@Override
public Object clone() {
// This will fail - Person.clone() returns Person, not Employee
Employee copy = (Employee) super.clone(); // ClassCastException!
copy.employeeId = this.employeeId;
// department is never properly cloned
return copy;
}
}
// Vulnerable: Using this.getClass() still wrong
public class BadCloner implements Cloneable {
private int value;
@Override
public Object clone() throws CloneNotSupportedException {
try {
// Still wrong - relies on reflection and no-arg constructor
BadCloner copy = this.getClass().getDeclaredConstructor().newInstance();
copy.value = this.value;
return copy;
} catch (Exception e) {
throw new CloneNotSupportedException();
}
}
}
// Subclass with required constructor parameters fails
public class RequiredArgsBadCloner extends BadCloner {
private String required;
public RequiredArgsBadCloner(String required) {
this.required = required;
}
// No no-arg constructor - parent's clone() fails!
}
Fixed Code
// Fixed: Proper clone() using super.clone()
public class Kibitzer implements Cloneable {
private String name;
private int rating;
public Kibitzer(String name, int rating) {
this.name = name;
this.rating = rating;
}
// Fixed: Always use super.clone()
@Override
public Object clone() throws CloneNotSupportedException {
// Correct! Object.clone() creates instance of actual runtime type
return super.clone();
// For this class with only primitives and immutable String,
// shallow copy from Object.clone() is sufficient
}
public String getName() { return name; }
public int getRating() { return rating; }
}
// Subclass now works correctly
public class FancyKibitzer extends Kibitzer {
private String title;
public FancyKibitzer(String name, int rating, String title) {
super(name, rating);
this.title = title;
}
@Override
public Object clone() throws CloneNotSupportedException {
// Now works! super.clone() returns FancyKibitzer
FancyKibitzer copy = (FancyKibitzer) super.clone();
// title is String (immutable) - shallow copy is fine
return copy;
}
public String getTitle() { return title; }
}
// Fixed: Proper clone with mutable fields
public class Person implements Cloneable {
private String name;
private Date birthDate;
private List<String> nicknames;
public Person() {}
public Person(String name, Date birthDate) {
this.name = name;
this.birthDate = birthDate;
this.nicknames = new ArrayList<>();
}
// Fixed: Use super.clone() and deep copy mutable fields
@Override
public Object clone() throws CloneNotSupportedException {
// First, get properly typed shallow copy
Person copy = (Person) super.clone();
// Deep copy mutable fields
if (this.birthDate != null) {
copy.birthDate = new Date(this.birthDate.getTime());
}
if (this.nicknames != null) {
copy.nicknames = new ArrayList<>(this.nicknames);
}
return copy;
}
// Getters and setters...
}
// Subclass now works correctly
public class Employee extends Person {
private String employeeId;
private Department department; // Assume Department is cloneable
@Override
public Object clone() throws CloneNotSupportedException {
// Works! Person.clone() uses super.clone() which returns Employee
Employee copy = (Employee) super.clone();
// Deep copy mutable fields specific to Employee
if (this.department != null) {
copy.department = (Department) this.department.clone();
}
return copy;
}
}
// Fixed: Complete example with proper cloning
public class Document implements Cloneable {
private String title;
private Date createdDate;
private Date modifiedDate;
private List<Section> sections;
private Map<String, String> metadata;
@Override
public Document clone() {
try {
// Use super.clone() for correct type
Document copy = (Document) super.clone();
// Deep copy all mutable fields
copy.createdDate = (Date) this.createdDate.clone();
copy.modifiedDate = (Date) this.modifiedDate.clone();
// Deep copy collections
copy.sections = new ArrayList<>();
for (Section section : this.sections) {
copy.sections.add(section.clone()); // Section must be Cloneable
}
copy.metadata = new HashMap<>(this.metadata);
return copy;
} catch (CloneNotSupportedException e) {
// Should never happen for Cloneable class
throw new AssertionError("Clone not supported", e);
}
}
}
// Alternative: Copy constructor (often preferred over clone)
public class SafePerson {
private final String name;
private final Date birthDate;
private final List<String> nicknames;
public SafePerson(String name, Date birthDate) {
this.name = name;
this.birthDate = new Date(birthDate.getTime()); // Defensive copy
this.nicknames = new ArrayList<>();
}
// Copy constructor - explicit and clear
public SafePerson(SafePerson other) {
this.name = other.name;
this.birthDate = new Date(other.birthDate.getTime());
this.nicknames = new ArrayList<>(other.nicknames);
}
// Static factory method alternative
public static SafePerson copyOf(SafePerson other) {
return new SafePerson(other);
}
}
// Subclass with copy constructor
public class SafeEmployee extends SafePerson {
private final String employeeId;
private final Department department;
public SafeEmployee(String name, Date birthDate,
String employeeId, Department department) {
super(name, birthDate);
this.employeeId = employeeId;
this.department = department; // Assume immutable or copy
}
// Copy constructor - clear inheritance
public SafeEmployee(SafeEmployee other) {
super(other); // Copy parent fields
this.employeeId = other.employeeId;
this.department = new Department(other.department); // Deep copy
}
public static SafeEmployee copyOf(SafeEmployee other) {
return new SafeEmployee(other);
}
}
// Using builder pattern for complex objects (another alternative)
public class ComplexDocument {
private final String title;
private final List<Section> sections;
private ComplexDocument(Builder builder) {
this.title = builder.title;
this.sections = new ArrayList<>(builder.sections);
}
// Create copy via builder
public Builder toBuilder() {
return new Builder()
.title(this.title)
.sections(new ArrayList<>(this.sections));
}
public static class Builder {
private String title;
private List<Section> sections = new ArrayList<>();
public Builder title(String title) {
this.title = title;
return this;
}
public Builder sections(List<Section> sections) {
this.sections = sections;
return this;
}
public ComplexDocument build() {
return new ComplexDocument(this);
}
}
}
CVE Examples
No specific CVEs are commonly attributed to this CWE, as it primarily affects application correctness rather than security.
References
- MITRE Corporation. "CWE-580: clone() Method Without super.clone()." https://cwe.mitre.org/data/definitions/580.html
- Joshua Bloch. "Effective Java" - Item 13: Override clone judiciously.
- Oracle. "Object.clone() Documentation."