New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default UUIDs used by EqualsVerifier have the same hashCode() #81

Closed
GoogleCodeExporter opened this Issue Mar 29, 2015 · 8 comments

Comments

Projects
None yet
1 participant
@GoogleCodeExporter

GoogleCodeExporter commented Mar 29, 2015

What steps will reproduce the problem?
1. EqualsVerifier.forClass(Client.class).suppress(Warning.NONFINAL_FIELDS, 
Warning.STRICT_INHERITANCE).verify();


What is the code (equals method, hashCode method, relevant fields) that
triggers the problem?
(simplified)
public class Client implements Serializable {
private UUID id;
@Override
public int hashCode() {
    return id!=null ? id.hashCode() : 0;
}
@Override
public boolean equals(Object object) {
    if (!(object instanceof Client)) {
        return false;
    }
    Client other=(Client) object;
    if ((this.id==null&&other.id!=null)||(this.id!=null&&!this.id.equals(other.id))) {
        return false;
    }
    return true;
}
}


What error message does EqualsVerifier give?
java.lang.AssertionError: Significant fields: equals relies on id, but hashCode 
does not.

What stacktrace does EqualsVerifier print, when called with the debug()
method?
java.lang.AssertionError: Significant fields: equals relies on id, but hashCode 
does not.
    at nl.jqno.equalsverifier.util.Assert.assertFalse(Assert.java:55)
    at nl.jqno.equalsverifier.FieldsChecker$SignificanceFieldCheck.execute(FieldsChecker.java:183)
    at nl.jqno.equalsverifier.FieldInspector.check(FieldInspector.java:37)
    at nl.jqno.equalsverifier.FieldsChecker.check(FieldsChecker.java:55)
    at nl.jqno.equalsverifier.EqualsVerifier.verifyWithExamples(EqualsVerifier.java:395)
    at nl.jqno.equalsverifier.EqualsVerifier.performVerification(EqualsVerifier.java:364)
    at nl.jqno.equalsverifier.EqualsVerifier.verify(EqualsVerifier.java:334)
    at ...ClientNGTest.testEquals(ClientNGTest.java:25)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:77)
    at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:189)
    at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:105)
    at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:117)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray2(ReflectionUtils.java:208)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:159)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:87)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:95)

What did you expect?
Success

What version of EqualsVerifier are you using?
1.2

Please provide any additional information below.

UUIDs used by EqualsVerifier have the same hashCode()

System.err.println(UUID.fromString("00000000-0000-0002-0000-000000000002").hashC
ode());
System.err.println(UUID.fromString("00000000-0000-0001-0000-000000000001").hashC
ode());

Original issue reported on code.google.com by rc.poi...@gmail.com on 21 May 2013 at 9:21

@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

Hi,

Sorry for the late reaction. It's been one of those weeks.

Anyway, your Client class passes just fine for me. However, it wouldn't be the 
first time that a Java API class is implemented slightly differently on 
different editions of the JDK, and that one of them works fine with EV whereas 
the other does not. So can you please tell me which JDK you use, and on which 
OS?


Also, can you tell me whether using .withPrefabValues solves the problem for 
you? You can use it like this:

EqualsVerifier.forClass(Client.class)
        .suppress(Warning.NONFINAL_FIELDS, Warning.STRICT_INHERITANCE)
        .withPrefabValues(UUID.class, UUID.randomUUID(), UUID.randomUUID())
        .verify();


Thanks!
Jan

Original comment by jan.ouw...@gmail.com on 26 May 2013 at 1:32

  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

Hi :)

$ java -version
java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (ArchLinux build 
7.u21_2.3.9-4-x86_64)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)


Yes, withPrefabValues was my workaround(except that I picked constant UUIDs for 
the slight chance that the random ones produce the same hashCode())

Regards,
Andreas

Original comment by rc.poi...@gmail.com on 26 May 2013 at 5:02

  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

Hi Andreas,

Interesting; we use the same JDK, so that can't be it. (Although mine is an 
Ubuntu release.) I still can't reproduce the error with the code you give me, 
though. However, looking at the implementation of UUID, I noticed that it uses 
a cached hashCode, which EqualsVerifier is unable to deal with. (I have Issue 
60 still open to solve that.)

So I will add UUID to the "default" list of prefabValues in the next version. 
Until then, the only way around it is to keep adding them to the list manually.

Original comment by jan.ouw...@gmail.com on 28 May 2013 at 8:45

  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

Ok, thank you :)

But just our of curiosity, do:
00000000-0000-0001-0000-000000000001
00000000-0000-0002-0000-000000000002

also both produce hashCode 0 on your system?

Original comment by rc.poi...@gmail.com on 28 May 2013 at 9:04

  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

UUID::hashCode():

public int hashCode() {
        long hilo = mostSigBits ^ leastSigBits;
        return ((int)(hilo >> 32)) ^ (int) hilo;
    }

Original comment by rc.poi...@gmail.com on 28 May 2013 at 9:06

  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

Hi Andreas,

Turns out we're using different JDKs after all: the Java on my path is Java 7, 
but Eclipse builds against Java 6. There I get the following implementation for 
UUID's hashCode method:

    public int hashCode() {
        if (hashCode == -1) {
            hashCode = (int)((mostSigBits >> 32) ^
                             mostSigBits ^
                             (leastSigBits >> 32) ^
                             leastSigBits);
        }
        return hashCode;
    }

So that explains why we're getting different results. And indeed, if I switch 
it to Java 7, I get the same results you do.

In both cases, I do get a hashCode of 0 for both UUIDs you mentioned.

So, thanks for the update! It was very enlightening for me :).

Original comment by jan.ouw...@gmail.com on 29 May 2013 at 8:14

  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

Hi Andreas,
I 
added UUID to the default list of prefabValues, in version 1.3.1, which is just 
released.

Jan

Original comment by jan.ouw...@gmail.com on 9 Jun 2013 at 3:31

  • Changed state: Fixed
  • Added labels: ****
  • Removed labels: ****
@GoogleCodeExporter

This comment has been minimized.

GoogleCodeExporter commented Mar 29, 2015

http://muhammadkhojaye.blogspot.co.uk/2010/02/java-hashing.html

Original comment by muhammad...@gmail.com on 10 Dec 2013 at 12:11

  • Added labels: ****
  • Removed labels: ****

jqno pushed a commit that referenced this issue Aug 23, 2016

Merge pull request #81 from muhasturk/master
removed unused <a> tag in _author-bio.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment