DEV Community

loading...

Why isn't the hashcode of a java object consistent on different hosts

jguo
perfect = () -> { while (true) { improving(); } }
・2 min read

Background

Recently, one of our API customers complains that the etag of our API is not working correctly. So, I started checking what's wrong. And what I found was that the etag across different hosts is not consistent. So, the etag is a hex string of java object hashcode. In the beginning, I had no idea what's wrong. Since the other APIs are working, only one of the API is not. So, I wrote a simple test code that prints each field on the object. Finally, I found the hashcode of java enum is different on different hosts. So why?

Why?

I just googled the question and found this post. It is exactly the same issue as I had.

Let's take a look java enum hashcode definition in the official document.

public final int hashCode()
Returns a hash code for this enum constant.
Overrides:
hashCode in class Object
Returns:
a hash code for this enum constant.
Enter fullscreen mode Exit fullscreen mode

See, what the problem is? Here, it says that it returns a hashcode for this enum constant. Enum constant is an object of the enum, and it is constant. So, it is consistent on the JVM. But, each JVM should have its own constant of the enum. That explains my question at the beginning. Enum’s on different JVMs will have different hash codes.

How to resolve the issue?

So, we know what is going on. But, how to resolve it. As you can see, the enum hashcode function is a final method. So, which means we can't override it.

This tells us that the only way to override the hashcode is the place where we use the enum object. Let's an example.

class TestDAO {
  private String test1;
  private Type type;

  enum Type {
    APPLE,
    ORANGE
  }
}
Enter fullscreen mode Exit fullscreen mode

Let's override the hashcode method on TestDAO.

class TestDAO {
  private String id;
  private Type type;

  @Override
  public hashCode(){
    Objects.hashCode(id, type.name());
  }

  @Override
  public equals(){
    ...
  }

  enum Type {
    APPLE,
    ORANGE
  }
}

Enter fullscreen mode Exit fullscreen mode

Note, the difference is that we use type.name() instead of the type itself. That resolves the issue. Not perfectly, but, works.

Reference:
https://madhead.me/posts/enums-fuckup/
https://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#hashCode()
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag

Discussion (0)