I have two classes: Address and Carrier. The first gets flagged for
mutability, while the second does not. The only difference I can see
between the two is that the latter (Carrier) has JPA annotations while
the former does not. Can you explain this better as it seems to me
that both should be mutable. The class bodies are below, followed by
the two corresponding tests.
===============================================================
public final class Address {
private String address1;
private String address2;
private String city;
private String state;
private String zip;
private String country;
public Address() {
super();
}
public String getAddress1() {
return address1;
}
public void setAddress1(String address1) {
this.address1 = address1;
}
public String getAddress2() {
return address2;
}
public void setAddress2(String address2) {
this.address2 = address2;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
if (zip != null && zip.length() > 5) {
this.zip = zip.substring(0, 5);
} else {
this.zip = zip;
}
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((address1 == null) ? 0 :
address1.hashCode());
result = PRIME * result + ((address2 == null) ? 0 :
address2.hashCode());
result = PRIME * result + ((city == null) ? 0 : city.hashCode());
result = PRIME * result + ((state == null) ? 0 : state.hashCode());
result = PRIME * result + ((zip == null) ? 0 : zip.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Address other = (Address) obj;
if (address1 == null) {
if (other.address1 != null)
return false;
} else if (!address1.equals(other.address1))
return false;
if (address2 == null) {
if (other.address2 != null)
return false;
} else if (!address2.equals(other.address2))
return false;
if (city == null) {
if (other.city != null)
return false;
} else if (!city.equals(other.city))
return false;
if (state == null) {
if (other.state != null)
return false;
} else if (!state.equals(other.state))
return false;
if (zip == null) {
if (other.zip != null)
return false;
} else if (!zip.equals(other.zip))
return false;
return true;
}
@Override
public String toString() {
return "Address [address1=[" + this.address1 + "]"
+ ", address2=[" + this.address2 + "]"
+ ", city=[" + this.city + "]"
+ ", country=[" + this.country + "]"
+ ", state=[" + this.state + "]"
+ ", zip=[" + this.zip + "]"
+ "]";
}
}
===============================================================
@Entity
@Table(name="table_name", schema="schema_name")
public final class Carrier {
private CarrierId id;
private String carrierDescription;
private String clientName;
public Carrier() {
super();
}
@Column (name="column_name")
public String getCarrierDescription() {
return carrierDescription;
}
public void setCarrierDescription(String carrierDescription) {
this.carrierDescription = carrierDescription;
}
@Transient
public String getCarrierId() {
return id.getCarrierId();
}
@Transient
public String getClientCode() {
return id.getClientCode();
}
@Column (name="column_name")
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
@Id
public CarrierId getId() {
return id;
}
public void setId(CarrierId id) {
this.id = id;
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((carrierDescription == null) ? 0 :
carrierDescription.hashCode());
result = PRIME * result + ((clientName == null) ? 0 :
clientName.hashCode());
result = PRIME * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Carrier other = (Carrier) obj;
if (carrierDescription == null) {
if (other.carrierDescription != null)
return false;
} else if (!carrierDescription.equals(other.carrierDescription))
return false;
if (clientName == null) {
if (other.clientName != null)
return false;
} else if (!clientName.equals(other.clientName))
return false;
if (id == null) {
if (
other.id != null)
return false;
} else if (!id.equals(
other.id))
return false;
return true;
}
@Override
public String toString() {
return "Carrier [carrierDescription=[" +
this.carrierDescription + "]"
+ ", clientName=[" + this.clientName + "]"
+ ", id=[" +
this.id + "]"
+ "]";
}
}
===============================================================
@Test
public void testHashCodeAndEqualsUsingEqualsVerifier() {
EqualsVerifier.forClass(Address.class).usingGetClass().verify(); //
this fails unless suppress(Warning.NONFINAL_FIELDS) is added
}
===============================================================
@Test
public void testHashCodeAndEqualsUsingEqualsVerifier() {
EqualsVerifier.forClass(Carrier.class).usingGetClass().verify(); //
this does not fail
}