Does org.json.JSONObject break Object.equals() contract? - java

With JSONObject you can make:
JSONObject.NULL.equals(null); //returns true
JSONObject.NULL breaks Object.equals() contract, at least it seems like it does, since
For any non-null reference value x, x.equals(null) should return false
The fact that this class is so widely used and supported makes me think that there is no violation for some reason, is there?

The NULL-Object is a pattern that is used to avoid checks like if(object == null).
It is the same thing here. The NULL is just a name. But what do you really have is not actually null (null-reference) but an object that gives a default-behavior (not-null reference).

It clearly violates the Object.equals() since
JSONObject.NULL is not null but a new Object()
Return value is true instead of false
JSONObject.NULL from source looks like below & the value is not null.
public static final Object NULL = new Object() {
#Override public boolean equals(Object o) {
return o == this || o == null; // API specifies this broken equals implementation
}
#Override public String toString() {
return "null";
}
};
equals() from Object looks like
public boolean equals(Object o) {
return this == o;
}
The additional comparison of o == null in JSONObject.NULL equals() method will always return true if we pass null. Hence
JSONObject.NULL.equals(null); //Will return true

Related

Class compare vs instanceof in equals method java

Like in a title:
My Entity looks like this:
#Entity
public class Example {
#Id
private Integer id;
private String name;
// fields, getters & setters ommited
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Example example = (Example) o;
return id != null ? id.equals(examle.id) : examle.id == null;
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
Auto generated equals method looks like above.
My questions are:
Why do I need to manually replace:
o == null || getClass() != o.getClass()
into
!(o instanceof
Example)
What will happen if the objects of this class will be placed in java.util.Set? In what part the rule of contract will be violated?
The main difference is that instanceof will return true if o has inheritance of the object whereas getClass comparation will check if both objects are strictly the same class.
As a rule of thumb, in your own classes it is almost always better to use
if (o == null || getClass() != o.getClass()) return false;
This is in particular the case when you plan to create subclasses of your class and override equals, but also when you're not planning that this will work without problem (in most cases). So you don't need to manually replace anything.
The reason is the following. The equals method is required to induce an equivalence relation on objects, in particular it is supposed to be symmetric: if a.equals(b) it must also be the case that b.equals(a) and vice versa. Many classes which use the equals method, such as maps and sets, assume this behavior.
Now, suppose you replace o == null || getClass() != o.getClass() with !(o instanceof Example), and create a subclass a follows:
class Subclass extends Example {
String address;
// fields, getters and setters
public boolean equals(Object o) {
if (!o instanceof Subclass) {
return false;
} else {
return super.equals(o) && Objects.equals(((Subclass)o).address, address);
}
}
}
Now consider the following code:
Example a = new Example();
a.setId(1);
a.setName("A");
Subclass b = new Subclass();
b.setId(1);
b.setName("A");
b.setAddress("Street 1");
System.out.println(a.equals(b)); // Prints true
System.out.println(b.equals(a)); // Prints false
You have now an equals method which is not symmetric, and this may lead to problems when using collections.
Note, however, that in some cases, you actually want to use instanceof. For example, the Javadoc for the equals method of the interface Set specifies that two sets are considered equal when they contain the same elements. So, a HashSet is equal to a TreeSet if they contain the same elements, even though the two sets belong to different classes. In such cases, of course, it is not appropriate to use getClass() == o.getClass()

this in equals method

I am looking at the equals method, and I see this and I don't understand what it means...I do understand them when I see it in constructors and some methods but its not clear to me when they are in equals method something like this:
(obj == this) ...what does this mean here ? where does it come from ?
I understand when it says something like this.name = name;
from a method like this
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
sorry it might be a duplicate but I couldnt find anything...
this is the current Object instance. Whenever you have a non-static method, it can only be called on an instance of your object.
You are comparing two objects for equality. The snippet:
if (obj == this) {
return true;
}
is a quick test that can be read
"If the object I'm comparing myself to is me, return true"
. You usually see this happen in equals methods so they can exit early and avoid other costly comparisons.
You have to look how this is called:
someObject.equals(someOtherObj);
This invokes the equals method on the instance of someObject. Now, inside that method:
public boolean equals(Object obj) {
if (obj == this) { //is someObject equal to obj, which in this case is someOtherObj?
return true;//If so, these are the same objects, and return true
}
You can see that this is referring to the instance of the object that equals is called on. Note that equals() is non-static, and so must be called only on objects that have been instantiated.
Note that == is only checking to see if there is referential equality; that is, the reference of this and obj are pointing to the same place in memory. Such references are naturally equal:
Object a = new Object();
Object b = a; //sets the reference to b to point to the same place as a
Object c = a; //same with c
b.equals(c);//true, because everything is pointing to the same place
Further note that equals() is generally used to also determine value equality. Thus, even if the object references are pointing to different places, it will check the internals to determine if those objects are the same:
FancyNumber a = new FancyNumber(2);//Internally, I set a field to 2
FancyNumber b = new FancyNumber(2);//Internally, I set a field to 2
a.equals(b);//true, because we define two FancyNumber objects to be equal if their internal field is set to the same thing.
this refers to the current instance of the class (object) your equals-method belongs to. When you test this against an object, the testing method (which is equals(Object obj) in your case) will check wether or not the object is equal to the current instance (referred to as this).
An example:
Object obj = this;
this.equals(obj); //true
Object obj = this;
new Object().equals(obj); //false

Canonical equals() method for Java as on Android Developers site

Here's how the site suggests you to write an equals() method.
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MyType)) {
return false;
}
MyType lhs = (MyType) o;
return primitiveField == lhs.primitiveField &&
referenceField.equals(lhs.referenceField) &&
(nullableField == null ? lhs.nullableField == null
: nullableField.equals(lhs.nullableField));
}
Now, I am surely misunderstanding something, but suppose you have two MyType objects m1 and m2, and e.g. if m1.referenceField is null, this is not going to work, because when it reaches
referenceField.equals(lhs.referenceField)
it will throw a NullPointerException. Where could be my logic error?
I believe the point is that this would be a type where referenceField was guaranteed to be non-null, e.g. it's checked in the constructor.
Compare this with nullableField, where the nullity is checked as part of equals.

Strange Findbugs error with equals

I have equals this method, but Findbugs is reporting error, any idea?
#Override
public boolean equals(final Object obj) {
return obj instanceof String && this.value != null
&& this.value.equals(obj); // this.value is a String
}
The error is :
Myclass.equals(Object) checks for operand being a String
Your implementation of equals for your MyClass will break at least the symmetric- and reflexive properties of the equals-contract:
symmetric:
for any non-null
reference values x and y, x.equals(y)
should return true if and only if
y.equals(x) returns true.
In your case:
MyClass A for example with value="a":
A.equals("a") will be true, but "a".equals(A) is false. This violates the symmetric-property.
reflexive:
for any non-null reference value x, x.equals(x) should return true.
But your implementation will return false for
A.equals(A)
but must return true.
Etc.
Your equals implementation sure is strange.
For one it looks very much like its violating the requirements of
a.equals(a) == true
=== Update in response to the comment ===
This is part of the contract of equals: http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals%28java.lang.Object%29
This kind of behavior is important when you put your Object into a Set or Map. Without the mentioned property you would get the weired behavior that you can add an instance to a Set and afterwards calling contains on the set with the exact same object as an argument would result in false.
=== Another update in response to your changed question ===
Since you check that the operand is a String, but your class isn't a subclass of String, an instance of your class will never be equal to itself according to your definition of equals. Also as stated by another answer symmetry will be broken.
This might be helpful as well:
http://findbugs.sourceforge.net/bugDescriptions.html#EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS
#Override
public boolean equals(final Object obj) {
return (obj instanceof YourClass) && (this.value.equals(((YourClass)obj).value)); // this.value is a String
}
As I understand Findbugs points to potential bugs.

Java null check why use == instead of .equals()

In Java I am told that when doing a null check one should use == instead of .equals(). What are the reasons for this?
They're two completely different things. == compares the object reference, if any, contained by a variable. .equals() checks to see if two objects are equal according to their contract for what equality means. It's entirely possible for two distinct object instances to be "equal" according to their contract. And then there's the minor detail that since equals is a method, if you try to invoke it on a null reference, you'll get a NullPointerException.
For instance:
class Foo {
private int data;
Foo(int d) {
this.data = d;
}
#Override
public boolean equals(Object other) {
if (other == null || other.getClass() != this.getClass()) {
return false;
}
return ((Foo)other).data == this.data;
}
/* In a real class, you'd override `hashCode` here as well */
}
Foo f1 = new Foo(5);
Foo f2 = new Foo(5);
System.out.println(f1 == f2);
// outputs false, they're distinct object instances
System.out.println(f1.equals(f2));
// outputs true, they're "equal" according to their definition
Foo f3 = null;
System.out.println(f3 == null);
// outputs true, `f3` doesn't have any object reference assigned to it
System.out.println(f3.equals(null));
// Throws a NullPointerException, you can't dereference `f3`, it doesn't refer to anything
System.out.println(f1.equals(f3));
// Outputs false, since `f1` is a valid instance but `f3` is null,
// so one of the first checks inside the `Foo#equals` method will
// disallow the equality because it sees that `other` == null
if you invoke .equals() on null you will get NullPointerException
So it is always advisble to check nullity before invoking method where ever it applies
if(str!=null && str.equals("hi")){
//str contains hi
}
Also See
difference-between-equals-and == in Java
In addition to the accepted answer (https://stackoverflow.com/a/4501084/6276704):
Since Java 1.7, if you want to compare two Objects which might be null, I recommend this function:
Objects.equals(onePossibleNull, twoPossibleNull)
java.util.Objects
This class consists of static utility methods for operating on
objects. These utilities include null-safe or null-tolerant methods
for computing the hash code of an object, returning a string for an
object, and comparing two objects.
Since:
1.7
In Java 0 or null are simple types and not objects.
The method equals() is not built for simple types. Simple types can be matched with ==.
Object.equals is null safe, however be aware that if two objects are null, object.equals will return true so be sure to check that the objects you are comparing aren't null (or hold null values) before using object.equals for comparison.
String firstname = null;
String lastname = null;
if(Objects.equals(firstname, lastname)){
System.out.println("equal!");
} else {
System.out.println("not equal!");
}
Example snippet above will return equal!
foo.equals(null)
What happens if foo is null?
You get a NullPointerException.
If an Object variable is null, one cannot call an equals() method upon it, thus an object reference check of null is proper.
If you try calling equals on a null object reference, then you'll get a null pointer exception thrown.
According to sources it doesn't matter what to use for default method implementation:
public boolean equals(Object object) {
return this == object;
}
But you can't be sure about equals in custom class.
If we use=> .equals method
if(obj.equals(null))
// Which mean null.equals(null) when obj will be null.
When your obj will be null it will throw Null Point Exception.
so we should use ==
if(obj == null)
it will compare the references.
here is an example where str != null but str.equals(null) when using org.json
JSONObject jsonObj = new JSONObject("{field :null}");
Object field = jsonObj.get("field");
System.out.println(field != null); // => true
System.out.println( field.equals(null)); //=> true
System.out.println( field.getClass()); // => org.json.JSONObject$Null
EDIT:
here is the org.json.JSONObject$Null class:
/**
* JSONObject.NULL is equivalent to the value that JavaScript calls null,
* whilst Java's null is equivalent to the value that JavaScript calls
* undefined.
*/
private static final class Null {
/**
* A Null object is equal to the null value and to itself.
*
* #param object
* An object to test for nullness.
* #return true if the object parameter is the JSONObject.NULL object or
* null.
*/
#Override
public boolean equals(Object object) {
return object == null || object == this;
}
}
Because equal is a function derived from Object class, this function compares items of the class. if you use it with null it will return false cause cause class content is not null. In addition == compares reference to an object.
So I never get confused and avoid problems with this solution:
if(str.trim().length() <=0 ) {
// is null !
}
I have encountered this case last night.
I determine that simply that:
Don't exist equals() method for null
So, you can not invoke an inexistent method if you don't have
-->>> That is reason for why we use == to check null
You code breaks Demeter's law. That's why it's better to refactor the design itself. As a workaround, you can use Optional
obj = Optional.ofNullable(object1)
.map(o -> o.getIdObject11())
.map(o -> o.getIdObject111())
.map(o -> o.getDescription())
.orElse("")
above is to check to hierarchy of a object so simply use
Optional.ofNullable(object1)
if you have only one object to check
Hope this helps !!!!
You could always do
if (str == null || str.equals(null))
This will first check the object reference and then check the object itself providing the reference isnt null.

Categories