I have an issue where I am trying to use test the equals method of a superclass using objects of a subclass:
My superclass is:
public class Excluded_DateTime implements Serializable {
private Date fromDate;
private Time fromTime;
private Date toDate;
private Time toTime;
private Valid active;
And the subclass differs by having an identifier as a key:
public class Classifier_Excluded_DateTime implements Serializable {
private Integer classifierExcludedDateTimeNo;
private Excluded_DateTime classifierExcludedDateTime;
So I want to test the equality of Classifier_Excluded_DateTime objects without using the field classifierExcludedDateTimeNo.
But what I am finding is that the equals method of the superclass is never called.
The NetBeans generated equals and hashCode methods of the superclass are as follows:
#Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + (this.fromDate != null ? this.fromDate.hashCode() : 0);
hash = 23 * hash + (this.fromTime != null ? this.fromTime.hashCode() : 0);
hash = 23 * hash + (this.toDate != null ? this.toDate.hashCode() : 0);
hash = 23 * hash + (this.toTime != null ? this.toTime.hashCode() : 0);
hash = 23 * hash + (this.active != null ? this.active.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Excluded_DateTime other = (Excluded_DateTime) obj;
if (this.fromDate != other.fromDate && (this.fromDate == null || !this.fromDate.equals(other.fromDate))) {
return false;
}
if (this.fromTime != other.fromTime && (this.fromTime == null || !this.fromTime.equals(other.fromTime))) {
return false;
}
if (this.toDate != other.toDate && (this.toDate == null || !this.toDate.equals(other.toDate))) {
return false;
}
if (this.toTime != other.toTime && (this.toTime == null || !this.toTime.equals(other.toTime))) {
return false;
}
if (this.active != other.active) {
return false;
}
return true;
}
And those of the subclass as follows:
#Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + (this.getClassifierExcludedDateTimeNo() != null ? this.getClassifierExcludedDateTimeNo().hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
if (! super.equals(obj)) {
return false;
}
final Classifier_Excluded_DateTime other = (Classifier_Excluded_DateTime) obj;
if (this.getClassifierExcludedDateTimeNo() != other.getClassifierExcludedDateTimeNo() && (this.getClassifierExcludedDateTimeNo() == null || !this.classifierExcludedDateTimeNo.equals(other.ClassifierExcludedDateTimeNo))) {
return false;
}
return true;
}
Can I do what I'm trying to do by amending these methods of either class?
I am trying to test whether two instance of Classifier_Excluded_DateTime are the same without including the field classifierExcludedDateTimeNo in the comparison.
You are not declaring Classifier_Excluded_DateTime as a subclass of Excluded_DateTime. To do that, you would need to say:
public class Classifier_Excluded_DateTime extends Excluded_DateTime {
Right now, it seems more like you are treating Excluded_DateTime as a kind of delegate of Classifier_Excluded_DateTime, as you have a member instance variable inside of Classifier_Excluded_DateTime that is of type Excluded_DateTime (the place where you say private Excluded_DateTime classifierExcludedDateTime;). I don't think that's your intent, since you are talking about subclasses and superclasses in your post.
(Update: removed error where I thought there was not an explicit super.equals() call).
Related
I have a person class with overridden hashcode and equals, looks something like this :
class PersonKey {
private String personUID;
private String ssnUID;
private String countryCode;
public PersonKey (
String personUID, String ssnUID, String countryCode) {
this.personUID= personUID;
this.ssnUID= countryCode;
this.countryCode= countryCode;
}
.....
}
This class already had personUID and ssnUID fields and I am introducing countryCode as a new field.
This class already had a complicated hashcode and equals method, with the inclusion of countryCode the logic got even more complicated. Is there a way I can reduce the Cyclomatic Complexity using inheritance or wrapper class?
HashCode :
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result;
if (personUID != null) result += personUID.hashCode();
else result += ((ssnUID == null) ? 0 : ssnUID.hashCode());
if ((personUID != null || ssnUID != null)
&& (countryCode != null)) {
result += countryCode.hashCode();
}
return result;
}
Equals :
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PersonKey other = (PersonKey) obj;
if (!getOuterType().equals(other.getOuterType())) {
return false;
}
// For the purposes of mapping any "empty" Person (null
// personUID and ssnUID) is considered to be unique so return
// false
if ((ssnUID == null) && (personUID == null)) {
return false;
}
// Only evaluate ssnUID if the personUID is null
if (personUID == null) {
// If the current ssnUID matches the personUID
// from the other key the keys will be assumed to match
if (ssnUID.equals(other.personUID)) {
if (StringUtils.isBlank(countryCode) && StringUtils.isBlank(other.countryCode)) {
return true;
} else {
if (countryCode.equals(other.contryCode)) return true;
}
} else if (other.personUID != null) {
return false;
}
if (ssnUID.equals(other.ssnUID)) {
if (StringUtils.isBlank(v) && StringUtils.isBlank(other.countryCode)) {
return true;
} else {
if (countryCode.equals(other.countryCode)) return true;
}
}
}
// If the current personUID matches the personUID
// the keys will
// be considered a match regardless of the value of the ssnUID.
else if (personUID .equals(other.personUID)) {
if (StringUtils.isBlank(contryCode) && StringUtils.isBlank(other.contryCode)) {
return true;
} else {
if (countryCode.equals(other.countryCode)) return true;
}
}
// If the current personUID matches the ssnUID
// from the other key, and the other keys personUID is null
// the keys will be considered a match
else if ((other.personUID == null)
&& (personUID.equals(other.ssnUID))) {
if (StringUtils.isBlank(contryCode) && StringUtils.isBlank(other.contryCode)) {
return true;
} else {
if (countryCode.equals(other.countryCode)) return true;
}
}
return false;
}
You can use Lombok's #EqualsAndHashCode would be the fastest option.
Example and documentation can be found here: https://projectlombok.org/features/EqualsAndHashCode
If you create a new method in your class:
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
class PersonKey {
private String personUID;
private String ssnUID;
private String countryCode;
...
#EqualsAndHashCode.Include
public String uidOrSsn() {
return personUID != null ? personUID : ssnUID;
}
}
This way you're telling Lombok to only create the equals and hashCode for the uidOrSsn() method declared. Whichever the non-null value of personUID or ssnUID, then it will be generated.
See the following 2 classes, DTO and DTOWithOrdering:
public class DTO {
private final String key;
private final long recordVersionNumber;
public DTO(String key) {
this.key = key;
this.recordVersionNumber = 0;
}
public DTO(String key, long recordVersionNumber) {
this.key = key;
this.recordVersionNumber = recordVersionNumber;
}
public String getKey() {
return key;
}
public long getRecordVersionNumber() {
return recordVersionNumber;
}
#Override
public String toString() {
return "Key: " + this.key + " Record Version Number: " + this.recordVersionNumber;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DTO that = (DTO) o;
return Objects.equal(this.key, that.key) &&
Objects.equal(this.recordVersionNumber, that.recordVersionNumber);
}
#Override
public int hashCode() {
return Objects.hashCode(key, recordVersionNumber);
}
public class DTOWithOrdering extends DTO implements Comparable<DTOWithOrdering> {
public DTOWithOrdering(String key, long recordVersionNumber) {
super(key, recordVersionNumber);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DTOWithOrdering other = (DTOWithOrdering) o;
if(this.getKey().equals(other.getKey())) {
if(this.getRecordVersionNumber() == other.getRecordVersionNumber()) {
return true;
} else if(this.getRecordVersionNumber() <= other.getRecordVersionNumber()) {
return true;
} else {
return false;
}
} {
return false;
}
}
#Override
public int compareTo(DTOWithOrdering other) {
if(this.getKey().equals(other.getKey())) {
if(this.getRecordVersionNumber() == other.getRecordVersionNumber()) {
return 0;
} else if(this.getRecordVersionNumber() <= other.getRecordVersionNumber()) {
return 0;
} else {
return -1;
}
} {
return -1;
}
}
}
DTOWIthOrdering extends from DTO and overrides the equals and compareTo methods.
The problem arises with the following code snippet when I create a TreeSet<DTOWIthOrdering> and invoke contains on this
TreeSet<DTOWithOrdering> treeSet = new TreeSet<DTOWithOrdering>(keyAndVersionList);
List<DTO> results = new ArrayList<DTO>();
for (DTO diff : diffs) {
if (treeSet.contains(new DTOWithOrdering(diff.getKey(), diff.getRecordVersionNumber())) == false) {
results.add(diff);
}
}
When I run this within my program I can see that treeSet contains 2700+ entities, one of which has a key of 0b3ae620-bbcf-347d-a9b4-87e6fd765cd7 and recordVersionNumber of 4
However, one of the diff entities contains the same key with a recordVersionNumber of 0.
When the code invokes the contains method, the set returns a value of false.
Strangely, for other examples, where the keys are equal and the record version number is greater in the TreeSet it returns true!
Is there something wrong here with my logic?
Here is a quote from JavaDoc for Comparable interface:
int compareTo(T o)
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object. The implementor
must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and
y. (This implies that x.compareTo(y) must throw an exception if
y.compareTo(x) throws an exception.)
If you return -1 but never return 1, the property
sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) cannot hold true. So your implementation of this method does not conform to the specification and TreeSet can work improperly.
I have below class.
Request.java
public class Request implements Serializable {
private String id;
private String name;
private String hid;
// getters and setters
// This class does not override any equals() and hashCode() methods
}
public class EmpRequest implements Serializable {
private Request request;
//Now here in this class I need override equals() and hashCode() methods based on **request**
}
In EmpRequest class, I need to override equals() and hashCode() based on properties of Request object.
If two request objects id is equal then i need to return true.
If two objects ids are not equal then i need to check for name and hid properties.
If name and hid properties of both the objects are equals then i need to return true.
Else false
How can I do that? I tried overriding equals() and hashCode() but eclipse gave me below the warning.
The field type 'com.mycompany.Request' does not implement equals() and hashCode() - the resulting code may not work correctly.
At the same type I cannot modify Request class as I don't have control over it.
How can I write equals() and hashCode() considering above conditions?
you can just generate equals() and hashCode() from IDE (Eclipse, IntelliJ IDEA) . That will enough for your scenario.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Result)) return false;
Result result = (Result) o;
if (hid != null ? !hid.equals(result.hid) : result.hid != null) return false;
if (id != null ? !id.equals(result.id) : result.id != null) return false;
if (name != null ? !name.equals(result.name) : result.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (hid != null ? hid.hashCode() : 0);
return result;
}
Edit:
public class Request implements Serializable{
private String id;
private String name;
private String hid;
public String getId()
{
return id;
}
public String getName()
{
return name;
}
public String getHid()
{
return hid;
}
}
public class EmpRequest implements Serializable{
private Request request;
public Request getRequest()
{
return request;
}
#Override
public boolean equals(Object obj) {
if(obj==null)
return false;
if(((EmpRequest) obj).getRequest().getId().equals(this.getRequest().getId()))
return true;
else if(((EmpRequest) obj).getRequest().getName().equals(this.getRequest().getName())
&&((EmpRequest) obj).getRequest().getHid().equals(this.getRequest().getHid())) {
return true;
}
else
return false;
}
}
Here is the hashcode too:
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((getRequest().getId() == null) ? 0 : getRequest().getId().hashCode());
result = prime * result + ((getRequest().getName() == null) ? 0 : getRequest().getName().hashCode());
result = prime * result + ((getRequest().getHid() == null) ? 0 : getRequest().getHid().hashCode());
return result;
}
Can anyone let me know what goes wrong in this piece of code? I'm pulling my hair out!
There isn't any problem if I use HashMap instead of ConcurrentHashMap. The code is compiled with JDK 5.0
public class MapTest {
public Map<DummyKey, DummyValue> testMap = new ConcurrentHashMap<DummyKey, DummyValue>();
public MapTest() {
DummyKey k1 = new DummyKey("A");
DummyValue v1 = new DummyValue("1");
DummyKey k2 = new DummyKey("B");
DummyValue v2 = new DummyValue("2");
testMap.put(k1, v1);
testMap.put(k2, v2);
}
public void printMap() {
for(DummyKey key : testMap.keySet()){
System.out.println(key.getKeyName());
DummyValue val = testMap.get(key);
System.out.println(val.getValue());
}
}
public static void main(String[] args){
MapTest main = new MapTest();
main.printMap();
}
private static class DummyKey {
private String keyName = "";
public DummyKey(String keyName){
this.keyName = keyName;
}
public String getKeyName() {
return keyName;
}
#Override
public int hashCode() {
return keyName.hashCode();
}
#Override
public boolean equals(Object o) {
return keyName.equals(o);
}
}
private static class DummyValue {
private String value = "";
public DummyValue(String value){
this.value = value;
}
public String getValue() {
return value;
}
}
}
This is the output:
B
Exception in thread "main" java.lang.NullPointerException
at test.MapTest.printMap(MapTest.java:27)
at test.MapTest.main(MapTest.java:34)
DummyKey.equals method implementation is incorrect, due to that testMap.get(key) always returns null. Try this
public boolean equals(Object o) {
if (o instanceof DummyKey) {
DummyKey other = (DummyKey) o;
return keyName == null ? other.keyName == null : keyName.equals(other.keyName);
}
return false;
}
hashCode also needs a little change to be consistent with equals
public int hashCode() {
return keyName == null ? 0 : keyName.hashCode();
}
The problem comes from your equals in DummyKey.
When you call DummyValue val = testMap.get(key);, the hashcode function finds a match (both keyname of k1 and key are the same and so are their hashcode). Yet equals returns false because k1.keyname is equal to "A" which is not equal to key itself, which is actually of type DummyValue: you are not comparing properly!
Therefore, you need to modify your equals function:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DummyKey other = (DummyKey) obj;
if (keyName == null) {
if (other.keyName != null)
return false;
} else if (!keyName.equals(other.keyName))
return false;
return true;
}
Please note that if you change hashCode(), then you must change equals() as well. Otherwise, you will run into problems. If equals() returns true for two items, then their hashCode() value must be equal! The opposite is not required but preferable for better hashing performance. Here is an implementation of equals() and hashCode().
HINT: if you are using eclipse, you can utilize its source generation capability to create the correct hashCode() and equals() method for you. The only thing you need to do is to pick the instance variables that identify the object. To do so in eclipse, while your source code is open, go to the tabs in the top and choose "source", then choose "Generate hashCode() and equals()..."
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
return result;
}
Override
public boolean equals(Object other) {
if(this == other) return true; //for optimization
if(! other instanceof this) return false; //also covers for when other == null
return this.keyName == null ? other.keyName == null : this.keyName.equals(other.keyName);
}
As others have pointed, the problem lies in the way you override hashcode and equals.
Two options : 1) Just remove the hashcode and equals and it works fine
2) I let eclipse generate the source for hashcode and equals and it works fine. This is what my eclipse belted out for me :
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((keyName == null) ? 0 : keyName.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;
DummyKey other = (DummyKey) obj;
if (keyName == null) {
if (other.keyName != null)
return false;
} else if (!keyName.equals(other.keyName))
return false;
return true;
}
Basically how do you check if an object is null or empty. What I mean is that if I have an object instantiated but all its values or fields are null, the how do I check in code if it is empty?
I have tried;
if (doc != null){
.... do something
But it doesn't seem to work.
You can't do it directly, you should provide your own way to check this. Eg.
class MyClass {
Object attr1, attr2, attr3;
public boolean isValid() {
return attr1 != null && attr2 != null && attr3 != null;
}
}
Or make all fields final and initialize them in constructors so that you can be sure that everything is initialized.
import org.apache.commons.lang3.ObjectUtils;
if(ObjectUtils.isEmpty(yourObject)){
//your block here
}
This can be done with java reflection,This method returns false if any one attribute value is present for the object ,hope it helps some one
public boolean isEmpty() {
for (Field field : this.getClass().getDeclaredFields()) {
try {
field.setAccessible(true);
if (field.get(this)!=null) {
return false;
}
} catch (Exception e) {
System.out.println("Exception occured in processing");
}
}
return true;
}
You should check it against null.
If you want to check if object x is null or not, you can do:
if(x != null)
But if it is not null, it can have properties which are null or empty. You will check those explicitly:
if(x.getProperty() != null)
For "empty" check, it depends on what type is involved. For a Java String, you usually do:
if(str != null && !str.isEmpty())
As you haven't mentioned about any specific problem with this, difficult to tell.
I suggest you add separate overloaded method and add them to your projects Utility/Utilities class.
To check for Collection be empty or null
public static boolean isEmpty(Collection obj) {
return obj == null || obj.isEmpty();
}
or use Apache Commons CollectionUtils.isEmpty()
To check if Map is empty or null
public static boolean isEmpty(Map<?, ?> value) {
return value == null || value.isEmpty();
}
or use Apache Commons MapUtils.isEmpty()
To check for String empty or null
public static boolean isEmpty(String string) {
return string == null || string.trim().isEmpty();
}
or use Apache Commons StringUtils.isBlank()
To check an object is null is easy but to verify if it's empty is tricky as object can have many private or inherited variables and nested objects which should all be empty. For that All need to be verified or some isEmpty() method be in all objects which would verify the objects emptiness.
If your Object contains Objects then check if they are null, if it have primitives check for their default values.
for Instance:
Person Object
name Property with getter and setter
to check if name is not initialized.
Person p = new Person();
if(p.getName()!=null)
I have a way, you guys tell me how good it is.
Create a new object of the class and compare it with your object (which you want to check for emptiness).
To be correctly able to do it :
Override the hashCode() and equals() methods of your model class and also of the classes, objects of whose are members of your class, for example :
Person class (primary model class) :
public class Person {
private int age;
private String firstName;
private String lastName;
private Address address;
//getters and setters
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + age;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
result = prime * result + ((lastName == null) ? 0 : lastName.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;
Person other = (Person) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (age != other.age)
return false;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
if (lastName == null) {
if (other.lastName != null)
return false;
} else if (!lastName.equals(other.lastName))
return false;
return true;
}
#Override
public String toString() {
return "Person [age=" + age + ", firstName=" + firstName + ", lastName=" + lastName + ", address=" + address
+ "]";
}
}
Address class (used inside Person class) :
public class Address {
private String line1;
private String line2;
//getters and setters
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((line1 == null) ? 0 : line1.hashCode());
result = prime * result + ((line2 == null) ? 0 : line2.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;
Address other = (Address) obj;
if (line1 == null) {
if (other.line1 != null)
return false;
} else if (!line1.equals(other.line1))
return false;
if (line2 == null) {
if (other.line2 != null)
return false;
} else if (!line2.equals(other.line2))
return false;
return true;
}
#Override
public String toString() {
return "Address [line1=" + line1 + ", line2=" + line2 + "]";
}
}
Now in the main class :
Person person1 = new Person();
person1.setAge(20);
Person person2 = new Person();
Person person3 = new Person();
if(person1.equals(person2)) --> this will be false
if(person2.equals(person3)) --> this will be true
I hope this is the best way instead of putting if conditions on each and every member variables.
Let me know !
for simple (It's worked in my project).
if null check not mandatory for some fields then exclude it from toString() method as in my above code, I have removed school.
public class Student {
private String name;
private String school;
private Integer roll;
private String section;
//getters and setters
#Override
public String toString() {
return "Student [name=" + name + ", roll=" + roll + ", section=" + section + "]";
}
}
public class StudentRunner {
public static void main(String[] args) {
Student s = new Student();
s.setName("ved");
s.setRoll(12);
s.setSection("A");
s.setSchool(null);//school set null and it removed from toString() method
if(s.toString().contains("null")) {
System.out.println("null value contains");
//do your work here or throw exception
} else {
System.out.println("no null value");
}
}
}
output : no null value
let suppose ,
data = {};
if( if(!$.isEmptyObject(data)))
{
document.write("Object is empty);
}
else{
document.write("Object is not empty);
}
It worked for me and its an easy way to check if object is empty or not