Details
-
Bug
-
Status: Closed
-
Critical
-
Resolution: Fixed
-
2.4.3
-
None
-
None
Description
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.
@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) } }
Both of the generated methods appear to be including bucket twice instead of including bucket and key.
see :7 and :29
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
see :152/:171 and :208/:219
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
Attachments
Issue Links
- relates to
-
GROOVY-7394 @ToString could support non-field properties
- Closed