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)