You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (JIRA)" <ji...@apache.org> on 2018/02/02 01:26:00 UTC
[jira] [Assigned] (GROOVY-7390) @EqualsAndHashCode incorrect when
using non-field properties
[ https://issues.apache.org/jira/browse/GROOVY-7390?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Paul King reassigned GROOVY-7390:
---------------------------------
Assignee: Paul King
> @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
> Assignee: Paul King
> Priority: Critical
> Fix For: 2.5.0-beta-3
>
>
> 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
(v7.6.3#76005)