Repository: apache/dubbo (Java)
Date: 2019-10-05 13:50:39+00:00
Task type: Bug Fix

Issue:
Some coding problems
- [x] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate.
- [x] I have checked the [FAQ](https://github.com/apache/dubbo/blob/master/FAQ.md) of this repository and believe that this is not a duplicate.

### Environment

* Dubbo version: 2.7.3
* Operating System version: Mac
* Java version: 1.8

### Steps to reproduce this issue

1.  `org/apache/dubbo/registry/support/ProviderConsumerRegTable.java:65` Type 'ProviderInvokerWrapper<>' does not define hashCode(), but is used in a hashing data-structure.
2. Class overrides equals but not hashCode.
* org.apache.dubbo.config.AbstractConfig
* org.apache.dubbo.registry.support.ProviderInvokerWrapper
* org.apache.dubbo.remoting.buffer.AbstractChannelBuffer

Pls. provide [GitHub address] to reproduce this issue.

### Expected Result

Whether the above suggestions can be fixed or have other considerations

### Actual Result

Is it considered a bug? Will it fix?



Issue discussion:
I think it's best to override the hashcode method, in some cases, it will go wrong if you don't rewrite it.

@LiosWong , I agree.  Is this problem solved by no one or not at all ?

Solution patch:
diff --git a/codestyle/checkstyle.xml b/codestyle/checkstyle.xml
--- a/codestyle/checkstyle.xml
+++ b/codestyle/checkstyle.xml
@@ -22,10 +22,12 @@
         <module name="UnusedImports"/>
         <module name="RedundantImport"/>
 
+        <module name="EqualsHashCode"/>
+
         <!--<module name="CustomImportOrder">-->
         <!--<property name="specialImportsRegExp" value="org.apache.dubbo.*"/>-->
         <!--<property name="sortImportsInGroupAlphabetically" value="false"/>-->
         <!--<property name="customImportOrderRules" value="SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE###STATIC"/>-->
         <!--</module>-->
     </module>
-</module>
\ No newline at end of file
+</module>
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@ -581,4 +581,31 @@ public boolean equals(Object obj) {
     public void addIntoConfigManager() {
         ApplicationModel.getConfigManager().addConfig(this);
     }
+
+    @Override
+    public int hashCode() {
+        int hashCode = 1;
+
+        Method[] methods = this.getClass().getMethods();
+        for (Method method : methods) {
+            if (MethodUtils.isGetter(method)) {
+                Parameter parameter = method.getAnnotation(Parameter.class);
+                if (parameter != null && parameter.excluded()) {
+                    continue;
+                }
+                try {
+                    Object value = method.invoke(this, new Object[]{});
+                    hashCode = 31 * hashCode + value.hashCode();
+                } catch (Exception ignored) {
+                    //ignored
+                }
+            }
+        }
+
+        if (hashCode == 0) {
+            hashCode = 1;
+        }
+
+        return hashCode;
+    }
 }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/AbstractChannelBuffer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/AbstractChannelBuffer.java
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/AbstractChannelBuffer.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/AbstractChannelBuffer.java
@@ -314,6 +314,11 @@ public boolean equals(Object o) {
                 && ChannelBuffers.equals(this, (ChannelBuffer) o);
     }
 
+    @Override
+    public int hashCode() {
+        return ChannelBuffers.hasCode(this);
+    }
+
     @Override
     public int compareTo(ChannelBuffer that) {
         return ChannelBuffers.compare(this, that);
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBuffers.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBuffers.java
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBuffers.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/buffer/ChannelBuffers.java
@@ -112,6 +112,24 @@ public static boolean equals(ChannelBuffer bufferA, ChannelBuffer bufferB) {
         return true;
     }
 
+    public static int hasCode(ChannelBuffer buffer){
+        final int aLen = buffer.readableBytes();
+        final int byteCount = aLen & 7;
+
+        int hashCode = 1;
+        int arrayIndex = buffer.readerIndex();
+
+        for (int i = byteCount; i > 0; i--) {
+            hashCode = 31 * hashCode + buffer.getByte(arrayIndex++);
+        }
+
+        if (hashCode == 0) {
+            hashCode = 1;
+        }
+
+        return hashCode;
+    }
+
     public static int compare(ChannelBuffer bufferA, ChannelBuffer bufferB) {
         final int aLen = bufferA.readableBytes();
         final int bLen = bufferB.readableBytes();


Test patch:
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/HeapChannelBufferTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/HeapChannelBufferTest.java
--- a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/HeapChannelBufferTest.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/buffer/HeapChannelBufferTest.java
@@ -16,7 +16,12 @@
  */
 package org.apache.dubbo.remoting.buffer;
 
+import org.hamcrest.MatcherAssert;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 
 public class HeapChannelBufferTest extends AbstractChannelBufferTest {
 
@@ -33,4 +38,19 @@ protected ChannelBuffer newBuffer(int capacity) {
     protected ChannelBuffer[] components() {
         return new ChannelBuffer[]{buffer};
     }
+
+    @Test
+    void testEqualsAndHashcode() {
+        HeapChannelBuffer b1 = new HeapChannelBuffer("hello-world".getBytes());
+        HeapChannelBuffer b2 = new HeapChannelBuffer("hello-world".getBytes());
+
+        MatcherAssert.assertThat(b1.equals(b2), is(true));
+        MatcherAssert.assertThat(b1.hashCode(), is(b2.hashCode()));
+
+        b1 = new HeapChannelBuffer("hello-world".getBytes());
+        b2 = new HeapChannelBuffer("hello-worldd".getBytes());
+
+        MatcherAssert.assertThat(b1.equals(b2), is(false));
+        MatcherAssert.assertThat(b1.hashCode(), not(b2.hashCode()));
+    }
 }