[ https://issues.apache.org/jira/browse/GROOVY-7390?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14533827#comment-14533827 ]
Paul King commented on GROOVY-7390: ----------------------------------- Just an update. I have a patch that fixes the issue for standard cases. It just doesn't handle tricky generics cases yet. I am hoping to have time to get the generics cases working before submitting the changes, > @EqualsAndHashCode incorrect when using non-field properties > ------------------------------------------------------------ > > Key: GROOVY-7390 > URL: https://issues.apache.org/jira/browse/GROOVY-7390 > Project: Groovy > Issue Type: Bug > Affects Versions: 2.4.3 > Reporter: Christopher Smith > Priority: Critical > > I have the following class representing a location in Amazon S3. Depending on > some inner business logic, I often need to split the object key into a prefix > and a file name, so I access them all through the {{getKey()}} method; with > S3, the only thing that matters is the final concatenated string. > The generated {{equals}} method incorrectly returns true for any two objects > with the same bucket, ignoring the key property. (I discovered this when I > got some interesting results out of a JSR-330 cache.) I have marked this > issue critical because it is likely to cause immediate security > vulnerabilities and data loss when unequal objects are found equal. > {code} > @CompileStatic > @EqualsAndHashCode(includes = ['bucket', 'key']) > final class S3ImageLocation implements ImageLocation { > @NotNull > final String bucket > final String prefix > @NotNull > final String subKey > @PersistenceConstructor > S3ImageLocation(String bucket, String prefix, String subKey) { > this.bucket = bucket > this.prefix = prefix > this.subKey = subKey > } > S3ImageLocation(String bucket, String subKey) { > this(bucket, null, subKey) > } > @JsonIgnore > String getKey() { > prefix ? "$prefix/$subKey" : subKey > } > @Override > String toString() { > "s3://$bucket/$key" > } > S3Location toBlitlineLocation() { > new S3Location(bucket, key) > } > } > {code} > Both of the generated methods appear to be including {{bucket}} twice instead > of including {{bucket}} and {{key}}. > see :7 and :29 > {code} > public int hashCode(); > Code: > 0: invokestatic #93 // Method > org/codehaus/groovy/util/HashCodeHelper.initHash:()I > 3: istore_1 > 4: iload_1 > 5: pop > 6: aload_0 > 7: ldc #94 // String bucket > 9: invokestatic #100 // Method > org/codehaus/groovy/runtime/InvokerHelper.getProperty:(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; > 12: aload_0 > 13: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 16: ifne 23 > 19: iconst_1 > 20: goto 24 > 23: iconst_0 > 24: ifeq 42 > 27: iload_1 > 28: aload_0 > 29: ldc #94 // String bucket > 31: invokestatic #100 // Method > org/codehaus/groovy/runtime/InvokerHelper.getProperty:(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; > 34: invokestatic #110 // Method > org/codehaus/groovy/util/HashCodeHelper.updateHash:(ILjava/lang/Object;)I > 37: istore_2 > 38: iload_2 > 39: istore_1 > 40: iload_2 > 41: pop > 42: iload_1 > 43: ireturn > 44: ldc #113 // int 0 > 46: ireturn > {code} > see :152/:171 and :208/:219 > {code} > public boolean equals(java.lang.Object); > Code: > 0: aload_1 > 1: ifnonnull 8 > 4: iconst_1 > 5: goto 9 > 8: iconst_0 > 9: ifeq 19 > 12: getstatic #129 // Field > java/lang/Boolean.FALSE:Ljava/lang/Boolean; > 15: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 18: ireturn > 19: aload_0 > 20: aload_1 > 21: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 24: ifeq 34 > 27: getstatic #132 // Field > java/lang/Boolean.TRUE:Ljava/lang/Boolean; > 30: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 33: ireturn > 34: aload_1 > 35: instanceof #2 // class > com/artsquare/studio/img/s3/S3ImageLocation > 38: ifne 45 > 41: iconst_1 > 42: goto 46 > 45: iconst_0 > 46: ifeq 56 > 49: getstatic #129 // Field > java/lang/Boolean.FALSE:Ljava/lang/Boolean; > 52: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 55: ireturn > 56: aload_1 > 57: ldc #2 // class > com/artsquare/studio/img/s3/S3ImageLocation > 59: invokestatic #138 // Method > org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType:(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object; > 62: checkcast #2 // class > com/artsquare/studio/img/s3/S3ImageLocation > 65: astore_2 > 66: aload_2 > 67: pop > 68: aload_2 > 69: aload_0 > 70: invokevirtual #140 // Method > canEqual:(Ljava/lang/Object;)Z > 73: ifne 80 > 76: iconst_1 > 77: goto 81 > 80: iconst_0 > 81: ifeq 91 > 84: getstatic #129 // Field > java/lang/Boolean.FALSE:Ljava/lang/Boolean; > 87: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 90: ireturn > 91: aload_0 > 92: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 95: aload_2 > 96: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 99: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 102: ifne 109 > 105: iconst_1 > 106: goto 110 > 109: iconst_0 > 110: ifeq 274 > 113: aload_0 > 114: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 117: aload_0 > 118: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 121: ifeq 147 > 124: aload_2 > 125: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 128: aload_2 > 129: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 132: ifne 139 > 135: iconst_1 > 136: goto 140 > 139: iconst_0 > 140: ifeq 147 > 143: iconst_1 > 144: goto 148 > 147: iconst_0 > 148: ifne 189 > 151: aload_0 > 152: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 155: aload_0 > 156: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 159: ifne 166 > 162: iconst_1 > 163: goto 167 > 166: iconst_0 > 167: ifeq 185 > 170: aload_2 > 171: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 174: aload_2 > 175: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 178: ifeq 185 > 181: iconst_1 > 182: goto 186 > 185: iconst_0 > 186: ifeq 193 > 189: iconst_1 > 190: goto 194 > 193: iconst_0 > 194: ifeq 207 > 197: getstatic #129 // Field > java/lang/Boolean.FALSE:Ljava/lang/Boolean; > 200: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 203: ireturn > 204: goto 274 > 207: aload_0 > 208: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 211: aload_0 > 212: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 215: ifeq 233 > 218: aload_2 > 219: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 222: aload_2 > 223: invokestatic #106 // Method > org/codehaus/groovy/runtime/DefaultGroovyMethods.is:(Ljava/lang/Object;Ljava/lang/Object;)Z > 226: ifeq 233 > 229: iconst_1 > 230: goto 234 > 233: iconst_0 > 234: ifne 241 > 237: iconst_1 > 238: goto 242 > 241: iconst_0 > 242: ifeq 274 > 245: aload_0 > 246: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 249: aload_2 > 250: invokevirtual #143 // Method > getBucket:()Ljava/lang/String; > 253: invokestatic #146 // Method > org/codehaus/groovy/runtime/ScriptBytecodeAdapter.compareEqual:(Ljava/lang/Object;Ljava/lang/Object;)Z > 256: ifne 263 > 259: iconst_1 > 260: goto 264 > 263: iconst_0 > 264: ifeq 274 > 267: getstatic #129 // Field > java/lang/Boolean.FALSE:Ljava/lang/Boolean; > 270: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 273: ireturn > 274: getstatic #132 // Field > java/lang/Boolean.TRUE:Ljava/lang/Boolean; > 277: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 280: ireturn > 281: ldc #113 // int 0 > 283: invokestatic #122 // Method > java/lang/Integer.valueOf:(I)Ljava/lang/Integer; > 286: invokestatic #58 // Method > org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.booleanUnbox:(Ljava/lang/Object;)Z > 289: ireturn > {code} -- This message was sent by Atlassian JIRA (v6.3.4#6332)